From 79cba12f46bc21a6ed8840292542965f8f039652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Fri, 20 Feb 2015 14:50:16 +0100 Subject: CMemSubPic: Resize subpic to fit into video frame. This resolves issues with anamorphic videos for VSFilter. Fixes #2516 --- src/SubPic/MemSubPic.cpp | 93 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 22 deletions(-) (limited to 'src/SubPic/MemSubPic.cpp') diff --git a/src/SubPic/MemSubPic.cpp b/src/SubPic/MemSubPic.cpp index 1505f4cb0..bd707c592 100644 --- a/src/SubPic/MemSubPic.cpp +++ b/src/SubPic/MemSubPic.cpp @@ -1,6 +1,6 @@ /* * (C) 2003-2006 Gabest - * (C) 2006-2014 see Authors.txt + * (C) 2006-2015 see Authors.txt * * This file is part of MPC-HC. * @@ -94,6 +94,9 @@ CMemSubPic::CMemSubPic(const SubPicDesc& spd) CMemSubPic::~CMemSubPic() { delete [] m_spd.bits; + if (m_resizedSpd) { + delete[] m_resizedSpd->bits; + } } // ISubPic @@ -106,8 +109,8 @@ STDMETHODIMP_(void*) CMemSubPic::GetObject() STDMETHODIMP CMemSubPic::GetDesc(SubPicDesc& spd) { spd.type = m_spd.type; - spd.w = m_size.cx; - spd.h = m_size.cy; + 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; @@ -130,6 +133,11 @@ STDMETHODIMP CMemSubPic::CopyTo(ISubPic* pSubPic) return E_FAIL; } + if (auto subPic = dynamic_cast(pSubPic)) { + // 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; @@ -181,26 +189,62 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) return S_OK; } - if (m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_AYUV) { + 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->h < r.Height() || m_resizedSpd->w < r.Width() || !m_resizedSpd->bits) { + delete[] m_resizedSpd->bits; + m_resizedSpd->bits = DEBUG_NEW BYTE[r.Width() * 4 * r.Height()]; + } + + 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. + delete[] m_resizedSpd->bits; + 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 (m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) { - m_rcDirty.left &= ~1; - m_rcDirty.right = (m_rcDirty.right + 1) & ~1; + if (subPic.type == MSP_YUY2 || subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + rcDirty.left &= ~1; + rcDirty.right = (rcDirty.right + 1) & ~1; - if (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) { - m_rcDirty.top &= ~1; - m_rcDirty.bottom = (m_rcDirty.bottom + 1) & ~1; + if (subPic.type == MSP_YV12 || subPic.type == MSP_IYUV) { + rcDirty.top &= ~1; + rcDirty.bottom = (rcDirty.bottom + 1) & ~1; } } } - int w = m_rcDirty.Width(), h = m_rcDirty.Height(); - BYTE* top = m_spd.bits + m_spd.pitch * m_rcDirty.top + m_rcDirty.left * 4; - BYTE* bottom = top + m_spd.pitch * h; + 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 (m_spd.type == MSP_RGB16) { - for (; top < bottom ; top += m_spd.pitch) { + if (subPic.type == MSP_RGB16) { + for (; top < bottom ; top += subPic.pitch) { DWORD* s = (DWORD*)top; DWORD* e = s + w; for (; s < e; s++) { @@ -208,8 +252,8 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) //*s = (*s&0xff000000)|((*s>>8)&0xf800)|((*s>>5)&0x07e0)|((*s>>3)&0x001f); } } - } else if (m_spd.type == MSP_RGB15) { - for (; top < bottom; top += m_spd.pitch) { + } else if (subPic.type == MSP_RGB15) { + for (; top < bottom; top += subPic.pitch) { DWORD* s = (DWORD*)top; DWORD* e = s + w; for (; s < e; s++) { @@ -217,8 +261,8 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) //*s = (*s&0xff000000)|((*s>>9)&0x7c00)|((*s>>6)&0x03e0)|((*s>>3)&0x001f); } } - } else if (m_spd.type == MSP_YUY2 || m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) { - for (; top < bottom ; top += m_spd.pitch) { + } 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 @@ -236,8 +280,8 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) } } } - } else if (m_spd.type == MSP_AYUV) { - for (; top < bottom ; top += m_spd.pitch) { + } else if (subPic.type == MSP_AYUV) { + for (; top < bottom ; top += subPic.pitch) { BYTE* s = top; BYTE* e = s + w * 4; @@ -373,7 +417,7 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) return E_POINTER; } - const SubPicDesc& src = m_spd; + const SubPicDesc& src = m_resizedSpd ? *m_resizedSpd : m_spd; SubPicDesc dst = *pTarget; // copy, because we might modify it if (src.type != dst.type) { @@ -382,6 +426,10 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) 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; @@ -600,6 +648,7 @@ bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) spd.bpp = 32; spd.pitch = (spd.w * spd.bpp) >> 3; spd.type = m_type; + spd.vidrect = m_curvidrect; try { spd.bits = DEBUG_NEW BYTE[spd.pitch * spd.h]; } catch (CMemoryException* e) { -- cgit v1.2.3 From 4a26ac6bbc288e1db97921b99ffc7561ddfe1cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Thu, 26 Feb 2015 18:15:09 +0100 Subject: CMemSubPicAllocator: Reuse allocated memory. --- src/SubPic/MemSubPic.cpp | 91 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 14 deletions(-) (limited to 'src/SubPic/MemSubPic.cpp') diff --git a/src/SubPic/MemSubPic.cpp b/src/SubPic/MemSubPic.cpp index bd707c592..19be4c12b 100644 --- a/src/SubPic/MemSubPic.cpp +++ b/src/SubPic/MemSubPic.cpp @@ -84,8 +84,9 @@ void ColorConvInit() // CMemSubPic // -CMemSubPic::CMemSubPic(const SubPicDesc& spd) - : m_spd(spd) +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); @@ -93,9 +94,9 @@ CMemSubPic::CMemSubPic(const SubPicDesc& spd) CMemSubPic::~CMemSubPic() { - delete [] m_spd.bits; + m_pAllocator->FreeSpdBits(m_spd); if (m_resizedSpd) { - delete[] m_resizedSpd->bits; + m_pAllocator->FreeSpdBits(*m_resizedSpd); } } @@ -134,6 +135,8 @@ STDMETHODIMP CMemSubPic::CopyTo(ISubPic* pSubPic) } 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); } @@ -202,9 +205,8 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) m_resizedSpd->pitch = r.Width() * 4; m_resizedSpd->bpp = m_spd.bpp; - if (m_resizedSpd->h < r.Height() || m_resizedSpd->w < r.Width() || !m_resizedSpd->bits) { - delete[] m_resizedSpd->bits; - m_resizedSpd->bits = DEBUG_NEW BYTE[r.Width() * 4 * r.Height()]; + 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 @@ -215,7 +217,7 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) rcDirty.SetRect(0, 0, m_resizedSpd->w, m_resizedSpd->h); } else if (m_resizedSpd) { // Resize is not needed so release m_resizedSpd. - delete[] m_resizedSpd->bits; + m_pAllocator->FreeSpdBits(*m_resizedSpd); m_resizedSpd = nullptr; } @@ -634,11 +636,20 @@ CMemSubPicAllocator::CMemSubPicAllocator(int type, SIZE 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) { + if (!ppSubPic || m_maxsize.cx <= 0 || m_maxsize.cy <= 0) { return false; } @@ -649,15 +660,13 @@ bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) spd.pitch = (spd.w * spd.bpp) >> 3; spd.type = m_type; spd.vidrect = m_curvidrect; - try { - spd.bits = DEBUG_NEW BYTE[spd.pitch * spd.h]; - } catch (CMemoryException* e) { - e->Delete(); + + if (!AllocSpdBits(spd)) { return false; } try { - *ppSubPic = DEBUG_NEW CMemSubPic(spd); + *ppSubPic = DEBUG_NEW CMemSubPic(spd, this); } catch (CMemoryException* e) { e->Delete(); delete [] spd.bits; @@ -668,3 +677,57 @@ bool CMemSubPicAllocator::Alloc(bool fStatic, ISubPic** ppSubPic) 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.end()) { + 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 (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; +} + +STDMETHODIMP CMemSubPicAllocator::SetCurVidRect(RECT curvidrect) +{ + m_curvidrect = curvidrect; + return __super::SetCurVidRect(curvidrect); +} -- cgit v1.2.3 From 3d4b2ddb05290322fb3b362d8e09b4e4ca2ba596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sun, 1 Mar 2015 15:38:59 +0100 Subject: Suppress type mismatch warnings. --- src/SubPic/MemSubPic.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/SubPic/MemSubPic.cpp') diff --git a/src/SubPic/MemSubPic.cpp b/src/SubPic/MemSubPic.cpp index 19be4c12b..c8b7c253d 100644 --- a/src/SubPic/MemSubPic.cpp +++ b/src/SubPic/MemSubPic.cpp @@ -62,7 +62,7 @@ void ColorConvInit() for (int i = 0; i < 256; i++) { clipBase[i] = 0; - clipBase[i + 256] = i; + clipBase[i + 256] = BYTE(i); clipBase[i + 512] = 255; } @@ -269,8 +269,8 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) BYTE* e = s + w * 4; for (; s < e; s += 8) { // ARGB ARGB -> AxYU AxYV if ((s[3] + s[7]) < 0x1fe) { - s[1] = (c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16; - s[5] = (c2y_yb[s[4]] + c2y_yg[s[5]] + c2y_yr[s[6]] + 0x108000) >> 16; + 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; @@ -289,7 +289,7 @@ STDMETHODIMP CMemSubPic::Unlock(RECT* pDirtyRect) for (; s < e; s += 4) { // ARGB -> AYUV if (s[3] < 0xff) { - int y = (c2y_yb[s[0]] + c2y_yg[s[1]] + c2y_yr[s[2]] + 0x108000) >> 16; + 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]; @@ -615,7 +615,7 @@ STDMETHODIMP CMemSubPic::AlphaBlt(RECT* pSrc, RECT* pDst, SubPicDesc* pTarget) 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 = (((*d2 - 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1); + *d2 = BYTE((((*d2 - 0x80) * ia) >> 8) + ((s2[0] + s2[src.pitch]) >> 1)); } } } -- cgit v1.2.3 From feecaa778567e489390de0ede6098950d76dfcab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Wed, 4 Mar 2015 01:25:16 +0100 Subject: CMemSubPicAllocator: Use cend() for consistency. --- src/SubPic/MemSubPic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/SubPic/MemSubPic.cpp') diff --git a/src/SubPic/MemSubPic.cpp b/src/SubPic/MemSubPic.cpp index c8b7c253d..defab054d 100644 --- a/src/SubPic/MemSubPic.cpp +++ b/src/SubPic/MemSubPic.cpp @@ -689,7 +689,7 @@ bool CMemSubPicAllocator::AllocSpdBits(SubPicDesc& spd) return std::get<0>(p) == size_t(spd.pitch) * spd.h; }); - if (it != m_freeMemoryChunks.end()) { + if (it != m_freeMemoryChunks.cend()) { spd.bits = std::get<1>(*it); m_freeMemoryChunks.erase(it); } else { -- cgit v1.2.3