diff options
author | Kacper Michajłow <kasper93@gmail.com> | 2017-08-13 04:02:21 +0300 |
---|---|---|
committer | Kacper Michajłow <kasper93@gmail.com> | 2017-08-13 23:24:42 +0300 |
commit | 701ceec81e37de1d9f89ce82ced9bab7735a2eae (patch) | |
tree | 377ecbd3230ac5711e3c7d2f8bcfe14d62ae80a0 /src/Subtitles | |
parent | f1bfa3c353f0f0929237f14c01f538a91589d9e0 (diff) |
Subtitles: Add cache for alpha mask.
Diffstat (limited to 'src/Subtitles')
-rw-r--r-- | src/Subtitles/RTS.cpp | 243 | ||||
-rw-r--r-- | src/Subtitles/RTS.h | 125 | ||||
-rw-r--r-- | src/Subtitles/RenderingCache.cpp | 28 | ||||
-rw-r--r-- | src/Subtitles/RenderingCache.h | 19 |
4 files changed, 291 insertions, 124 deletions
diff --git a/src/Subtitles/RTS.cpp b/src/Subtitles/RTS.cpp index d52d80ea6..c61f4ad58 100644 --- a/src/Subtitles/RTS.cpp +++ b/src/Subtitles/RTS.cpp @@ -1,6 +1,6 @@ /*
* (C) 2003-2006 Gabest
- * (C) 2006-2016 see Authors.txt
+ * (C) 2006-2017 see Authors.txt
*
* This file is part of MPC-HC.
*
@@ -38,6 +38,15 @@ static long revcolor(long c) //////////////////////////////////////////////////////////////////////////////////////////////
+void alpha_mask_deleter::operator()(CAlphaMask* ptr) const noexcept
+{
+ m_alphaMaskPool.emplace_front(std::move(*ptr));
+ std::default_delete<CAlphaMask>()(ptr);
+ if (m_alphaMaskPool.size() > 10) {
+ m_alphaMaskPool.pop_back();
+ }
+}
+
// CMyFont
CMyFont::CMyFont(const STSStyle& style)
@@ -786,25 +795,30 @@ CClipper::CClipper(CStringW str, const CSize& size, double scalex, double scaley , m_inverse(inverse)
, m_cpOffset(cpOffset)
, m_pAlphaMask(nullptr)
+ , m_effectType(-1)
{
- if (m_size.cx <= 0 || m_size.cy <= 0) {
- return;
+}
+
+CAlphaMaskSharedPtr CClipper::GetAlphaMask(const std::shared_ptr<CClipper>& clipper)
+{
+ if (m_pAlphaMask) {
+ return m_pAlphaMask;
}
- const size_t alphaMaskSize = size_t(m_size.cx) * m_size.cy;
+ ASSERT(this == clipper.get());
+ if (m_size.cx <= 0 || m_size.cy <= 0) {
+ return nullptr;
+ }
- try {
- m_pAlphaMask = DEBUG_NEW BYTE[alphaMaskSize];
- } catch (CMemoryException* e) {
- e->Delete();
- return;
+ CClipperKey key(clipper);
+ if (m_renderingCaches.alphaMaskCache.Lookup(key, m_pAlphaMask)) {
+ return m_pAlphaMask;
}
- memset(m_pAlphaMask, (m_inverse ? 0x40 : 0), alphaMaskSize);
Paint(CPoint(0, 0), CPoint(0, 0));
if (!m_pOverlayData) {
- return;
+ return nullptr;
}
int w = m_pOverlayData->mOverlayWidth, h = m_pOverlayData->mOverlayHeight;
@@ -830,17 +844,31 @@ CClipper::CClipper(CStringW str, const CSize& size, double scalex, double scaley }
if (w <= 0 || h <= 0) {
- return;
+ 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();
+
const BYTE* src = m_pOverlayData->mpOverlayBufferBody + m_pOverlayData->mOverlayPitch * yo + xo;
- BYTE* dst = m_pAlphaMask + m_size.cx * y + x;
+ BYTE* dst = pAlphaMask + m_size.cx * y + x;
+ memset(pAlphaMask, (m_inverse ? 0x40 : 0), 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];
}
+ memset(dst + w, 0x40, m_size.cx - w);
src += m_pOverlayData->mOverlayPitch;
dst += m_size.cx;
@@ -848,15 +876,94 @@ CClipper::CClipper(CStringW str, const CSize& size, double scalex, double scaley } else {
for (ptrdiff_t i = 0; i < h; ++i) {
memcpy(dst, src, w * sizeof(BYTE));
+ memset(dst + w, 0, m_size.cx - w);
src += m_pOverlayData->mOverlayPitch;
dst += m_size.cx;
}
}
-}
+ memset(dst, (m_inverse ? 0x40 : 0), alphaMaskSize - (dst - pAlphaMask));
-CClipper::~CClipper()
-{
- SAFE_DELETE_ARRAY(m_pAlphaMask);
+ 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()
@@ -1142,7 +1249,7 @@ void CSubtitle::Empty() EmptyEffects();
- SAFE_DELETE(m_pClipper);
+ m_pClipper.reset();
}
void CSubtitle::EmptyEffects()
@@ -1312,10 +1419,7 @@ void CSubtitle::CreateClippers(CSize size) 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 = DEBUG_NEW CClipper(str, size, 1.0, 1.0, false, CPoint(0, 0), m_renderingCaches);
- if (!m_pClipper->m_pAlphaMask) {
- SAFE_DELETE(m_pClipper);
- }
+ m_pClipper = std::make_shared<CClipper>(str, size, 1.0, 1.0, false, CPoint(0, 0), m_renderingCaches);
} catch (CMemoryException* e) {
e->Delete();
}
@@ -1327,87 +1431,12 @@ void CSubtitle::CreateClippers(CSize size) if (!m_pClipper && !createClipper(size)) {
return;
}
-
- int width = m_effects[EF_BANNER]->param[2];
- int w = size.cx, h = size.cy;
- int da = (64 << 8) / width;
- BYTE* am = m_pClipper->m_pAlphaMask;
-
- for (ptrdiff_t j = 0; j < h; j++, am += w) {
- int a = 0;
- int k = std::min(width, w);
-
- for (ptrdiff_t i = 0; i < k; i++, a += da) {
- am[i] = BYTE((am[i] * a) >> 14);
- }
-
- a = 0x40 << 8;
- k = w - width;
-
- if (k < 0) {
- a -= -k * da;
- k = 0;
- }
-
- for (ptrdiff_t i = k; i < w; i++, a -= da) {
- am[i] = BYTE((am[i] * a) >> 14);
- }
- }
+ 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;
}
-
- int height = m_effects[EF_SCROLL]->param[4];
- int w = size.cx, h = size.cy;
- int da = (64 << 8) / height;
- int a = 0;
- int k = m_effects[EF_SCROLL]->param[0] >> 3;
- int l = k + height;
- if (k < 0) {
- a += -k * da;
- k = 0;
- }
- if (l > h) {
- l = h;
- }
-
- if (k < h) {
- BYTE* am = &m_pClipper->m_pAlphaMask[k * w];
-
- ZeroMemory(m_pClipper->m_pAlphaMask, am - m_pClipper->m_pAlphaMask);
-
- for (ptrdiff_t j = k; j < l; j++, a += da) {
- for (ptrdiff_t i = 0; i < w; i++, am++) {
- *am = BYTE(((*am) * a) >> 14);
- }
- }
- }
-
- da = -(64 << 8) / height;
- a = 0x40 << 8;
- l = m_effects[EF_SCROLL]->param[1] >> 3;
- k = l - height;
- if (k < 0) {
- a += -k * da;
- k = 0;
- }
- if (l > h) {
- l = h;
- }
-
- if (k < h) {
- BYTE* am = &m_pClipper->m_pAlphaMask[k * w];
-
- int j = k;
- for (; j < l; j++, a += da) {
- for (ptrdiff_t i = 0; i < w; i++, am++) {
- *am = BYTE(((*am) * a) >> 14);
- }
- }
-
- ZeroMemory(am, (h - j)*w);
- }
+ m_pClipper->SetEffect(*m_effects[EF_SCROLL], EF_SCROLL);
}
}
@@ -2169,18 +2198,18 @@ bool CRenderedTextSubtitle::CreateSubFromSSATag(CSubtitle* sub, const SSATagsLis size_t nParamsInt = tag.paramsInt.GetCount();
if (nParams == 1 && nParamsInt == 0 && !sub->m_pClipper) {
- sub->m_pClipper = DEBUG_NEW CClipper(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3), sub->m_scalex, sub->m_scaley,
- invert, (sub->m_relativeTo == STSStyle::VIDEO) ? CPoint(m_vidrect.left, m_vidrect.top) : CPoint(0, 0),
- m_renderingCaches);
+ sub->m_pClipper = std::make_shared<CClipper>(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3), sub->m_scalex, sub->m_scaley,
+ 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;
}
- sub->m_pClipper = DEBUG_NEW CClipper(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3),
- sub->m_scalex / (1 << (scale - 1)), sub->m_scaley / (1 << (scale - 1)), invert,
- (sub->m_relativeTo == STSStyle::VIDEO) ? CPoint(m_vidrect.left, m_vidrect.top) : CPoint(0, 0),
- m_renderingCaches);
+ sub->m_pClipper = std::make_shared<CClipper>(tag.params[0], CSize(m_size.cx >> 3, m_size.cy >> 3),
+ sub->m_scalex / (1 << (scale - 1)), sub->m_scaley / (1 << (scale - 1)), 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;
@@ -2993,7 +3022,7 @@ STDMETHODIMP CRenderedTextSubtitle::Render(SubPicDesc& spd, REFERENCE_TIME rt, d CPoint org2;
- BYTE* pAlphaMask = s->m_pClipper ? s->m_pClipper->m_pAlphaMask : nullptr;
+ BYTE* pAlphaMask = s->m_pClipper ? s->m_pClipper->GetAlphaMask(s->m_pClipper)->get() : nullptr;
for (int k = 0; k < EF_NUMBEROFEFFECTS; k++) {
if (!s->m_effects[k]) {
diff --git a/src/Subtitles/RTS.h b/src/Subtitles/RTS.h index 0e29b97d2..ad275c60d 100644 --- a/src/Subtitles/RTS.h +++ b/src/Subtitles/RTS.h @@ -1,6 +1,6 @@ /*
* (C) 2003-2006 Gabest
- * (C) 2006-2015 see Authors.txt
+ * (C) 2006-2015, 2017 see Authors.txt
*
* This file is part of MPC-HC.
*
@@ -21,21 +21,63 @@ #pragma once
+#include <list>
#include <memory>
#include "STS.h"
#include "Rasterizer.h"
#include "../SubPic/SubPicProviderImpl.h"
#include "RenderingCache.h"
+class Effect;
struct CTextDims;
struct CPolygonPath {
CAtlArray<BYTE> typesOrg;
CAtlArray<CPoint> pointsOrg;
CSize size;
};
+
+struct CAlphaMask;
+
+struct alpha_mask_deleter {
+ explicit alpha_mask_deleter(std::list<CAlphaMask>& alphaMaskPool)
+ : m_alphaMaskPool(alphaMaskPool) {
+ }
+
+ void operator()(CAlphaMask* ptr) const noexcept;
+
+ std::list<CAlphaMask>& m_alphaMaskPool;
+};
+
+struct CAlphaMask final : std::unique_ptr<BYTE[]> {
+ CAlphaMask() = delete;
+ CAlphaMask(CAlphaMask&&) = default;
+ CAlphaMask(const CAlphaMask&) = delete;
+ CAlphaMask& operator=(const CAlphaMask&) = delete;
+
+ size_t m_size;
+
+ explicit CAlphaMask(size_t size)
+ : std::unique_ptr<BYTE[]>(std::make_unique<BYTE[]>(size))
+ , m_size(size) {
+ }
+
+ static std::shared_ptr<CAlphaMask> Alloc(std::list<CAlphaMask>& alphaMaskPool, size_t size) {
+ for (auto it = alphaMaskPool.begin(); it != alphaMaskPool.end(); ++it) {
+ auto& am = *it;
+ if (am.m_size >= size) {
+ auto ret = std::shared_ptr<CAlphaMask>(DEBUG_NEW CAlphaMask(std::move(am)), alpha_mask_deleter(alphaMaskPool));
+ alphaMaskPool.erase(it);
+ return std::move(ret);
+ }
+ }
+ return std::shared_ptr<CAlphaMask>(DEBUG_NEW CAlphaMask(size), alpha_mask_deleter(alphaMaskPool));
+ }
+};
+
typedef std::shared_ptr<CPolygonPath> CPolygonPathSharedPtr;
struct SSATag;
typedef std::shared_ptr<CAtlList<SSATag>> SSATagsList;
+typedef std::shared_ptr<CAlphaMask> CAlphaMaskSharedPtr;
typedef CRenderingCache<CTextDimsKey, CTextDims, CKeyTraits<CTextDimsKey>> CTextDimsCache;
typedef CRenderingCache<CPolygonPathKey, CPolygonPathSharedPtr, CKeyTraits<CPolygonPathKey>> CPolygonCache;
@@ -43,6 +85,7 @@ typedef CRenderingCache<CStringW, SSATagsList, CStringElementTraits<CStringW>> C typedef CRenderingCache<CEllipseKey, CEllipseSharedPtr, CKeyTraits<CEllipseKey>> CEllipseCache;
typedef CRenderingCache<COutlineKey, COutlineDataSharedPtr, CKeyTraits<COutlineKey>> COutlineCache;
typedef CRenderingCache<COverlayKey, COverlayDataSharedPtr, CKeyTraits<COverlayKey>> COverlayCache;
+typedef CRenderingCache<CClipperKey, CAlphaMaskSharedPtr, CKeyTraits<CClipperKey>> CAlphaMaskCache;
struct RenderingCaches {
CTextDimsCache textDimsCache;
@@ -51,6 +94,9 @@ struct RenderingCaches { CEllipseCache ellipseCache;
COutlineCache outlineCache;
COverlayCache overlayCache;
+ // Be careful about the order alphaMaskCache need to be destroyed before alphaMaskPool.
+ std::list<CAlphaMask> alphaMaskPool;
+ CAlphaMaskCache alphaMaskCache;
RenderingCaches()
: textDimsCache(2048)
@@ -58,7 +104,8 @@ struct RenderingCaches { , SSATagsCache(2048)
, ellipseCache(64)
, outlineCache(128)
- , overlayCache(128) {}
+ , overlayCache(128)
+ , alphaMaskCache(128) {}
};
class CMyFont : public CFont
@@ -154,6 +201,20 @@ public: virtual bool Append(CWord* w);
};
+class Effect
+{
+public:
+ enum eftype type;
+ int param[9];
+ int t[4];
+
+ bool operator==(const Effect& rhs) const {
+ return type == rhs.type
+ && !memcmp(param, rhs.param, sizeof(param))
+ && !memcmp(t, rhs.t, sizeof(t));
+ }
+};
+
class CClipper : public CPolygon
{
private:
@@ -163,14 +224,60 @@ private: public:
CClipper(CStringW str, const CSize& size, double scalex, double scaley, bool inverse, const CPoint& cpOffset,
RenderingCaches& renderingCaches);
- virtual ~CClipper();
+ void CClipper::SetEffect(const Effect& effect, int effectType) {
+ m_effectType = effectType;
+ m_effect = effect;
+ }
+
+ CAlphaMaskSharedPtr GetAlphaMask(const std::shared_ptr<CClipper>& clipper);
+
+ ULONG Hash() const {
+ ULONG hash = CStringElementTraits<CString>::Hash(m_str);
+ hash += hash << 5;
+ hash += m_inverse;
+ hash += hash << 5;
+ hash += m_effectType;
+ hash += hash << 5;
+ hash += m_size.cx;
+ hash += hash << 5;
+ hash += m_size.cy;
+ hash += hash << 5;
+ hash += int(m_scalex * 1e6);
+ hash += hash << 5;
+ hash += int(m_scaley * 1e6);
+ for (const auto& param : m_effect.t) {
+ hash += hash << 5;
+ hash += param;
+ }
+ for (const auto& type : m_effect.t) {
+ hash += hash << 5;
+ hash += type;
+ }
+ return hash;
+ }
+
+ bool operator==(const CClipper& rhs) const {
+ return m_str == rhs.m_str
+ && std::abs(m_scalex - rhs.m_scalex) < 1e-6
+ && std::abs(m_scaley - rhs.m_scaley) < 1e-6
+ && m_size == rhs.m_size
+ && m_inverse == rhs.m_inverse
+ && m_effectType == rhs.m_effectType
+ && m_effect == rhs.m_effect;
+ }
+
+private:
const CSize m_size;
const bool m_inverse;
const CPoint m_cpOffset;
- BYTE* m_pAlphaMask;
+ CAlphaMaskSharedPtr m_pAlphaMask;
+ Effect m_effect;
+ int m_effectType;
};
+using CClipperSharedPtr = std::shared_ptr<CClipper>;
+
class CLine : public CAtlList<CWord*>
{
public:
@@ -278,14 +385,6 @@ enum eftype { #define EF_NUMBEROFEFFECTS 5
-class Effect
-{
-public:
- enum eftype type;
- int param[9];
- int t[4];
-};
-
class CSubtitle : public CAtlList<CLine*>
{
RenderingCaches& m_renderingCaches;
@@ -306,7 +405,7 @@ public: CAtlList<CWord*> m_words;
- CClipper* m_pClipper;
+ CClipperSharedPtr m_pClipper;
CRect m_rect, m_clip;
int m_topborder, m_bottomborder;
diff --git a/src/Subtitles/RenderingCache.cpp b/src/Subtitles/RenderingCache.cpp index 53b27e3bc..7a8bdd585 100644 --- a/src/Subtitles/RenderingCache.cpp +++ b/src/Subtitles/RenderingCache.cpp @@ -1,5 +1,5 @@ /* - * (C) 2013-2014, 2016 see Authors.txt + * (C) 2013-2014, 2016-2017 see Authors.txt * * This file is part of MPC-HC. * @@ -125,9 +125,9 @@ void COutlineKey::UpdateHash() // CreatePath m_hash = __super::GetHash(); m_hash += m_hash << 5; - m_hash += int(m_scalex); + m_hash += int(m_scalex * 1e6); m_hash += m_hash << 5; - m_hash += int(m_scaley); + m_hash += int(m_scaley * 1e6); m_hash += m_hash << 5; // Transform m_hash += int(m_style->fontScaleX); @@ -206,3 +206,25 @@ bool COverlayKey::operator==(const COverlayKey& overlayKey) const && m_style->fBlur == overlayKey.m_style->fBlur && IsNearlyEqual(m_style->fGaussianBlur, overlayKey.m_style->fGaussianBlur, 1e-6); } + +CClipperKey::CClipperKey(const std::shared_ptr<CClipper>& clipper) + : m_clipper(clipper) +{ + UpdateHash(); +} + +void CClipperKey::UpdateHash() +{ + m_hash = m_clipper->Hash(); +} + +bool CClipperKey::operator==(const CClipperKey& clipperKey) const +{ + if (m_clipper == clipperKey.m_clipper) { + return true; + } + if (m_clipper && clipperKey.m_clipper) { + return *m_clipper == *clipperKey.m_clipper; + } + return false; +} diff --git a/src/Subtitles/RenderingCache.h b/src/Subtitles/RenderingCache.h index 218da59da..5981708f4 100644 --- a/src/Subtitles/RenderingCache.h +++ b/src/Subtitles/RenderingCache.h @@ -1,5 +1,5 @@ /* - * (C) 2013-2014 see Authors.txt + * (C) 2013-2014, 2017 see Authors.txt * * This file is part of MPC-HC. * @@ -191,3 +191,20 @@ public: bool operator==(const COverlayKey& overlayKey) const; }; + +class CClipper; + +class CClipperKey +{ + ULONG m_hash; + std::shared_ptr<CClipper> m_clipper; + +public: + CClipperKey(const std::shared_ptr<CClipper>& clipper); + + ULONG GetHash() const { return m_hash; }; + + void UpdateHash(); + + bool operator==(const CClipperKey& clipperKey) const; +}; |