diff --git a/projects/RPi/patches/xbmc/xbmc-001-newclock3.patch b/projects/RPi/patches/xbmc/xbmc-001-newclock4.patch similarity index 65% rename from projects/RPi/patches/xbmc/xbmc-001-newclock3.patch rename to projects/RPi/patches/xbmc/xbmc-001-newclock4.patch index 7844a6299c..6e35e335f0 100644 --- a/projects/RPi/patches/xbmc/xbmc-001-newclock3.patch +++ b/projects/RPi/patches/xbmc/xbmc-001-newclock4.patch @@ -1,7337 +1,959 @@ -From d819358e36fda80a9835d001617fbbc592975f3d Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 11 Dec 2013 17:21:54 +0000 -Subject: [PATCH 01/98] Move the reference-counting of Begin and End calls from - DX and GL source files into GUIFontTTF.cpp. +From 6a095dba6f512c2c78158feb4f764b6ddc5b1d3e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 18 Aug 2014 17:48:04 +0100 +Subject: [PATCH 01/77] omxplayer: Reset codec on flush to stop a stale + timestamp from being returned --- - xbmc/guilib/GUIFontTTF.cpp | 21 ++++++ - xbmc/guilib/GUIFontTTF.h | 6 +- - xbmc/guilib/GUIFontTTFDX.cpp | 79 ++++++++++------------ - xbmc/guilib/GUIFontTTFDX.h | 4 +- - xbmc/guilib/GUIFontTTFGL.cpp | 154 ++++++++++++++++++++----------------------- - xbmc/guilib/GUIFontTTFGL.h | 4 +- - 6 files changed, 135 insertions(+), 133 deletions(-) + xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 2 ++ + 1 file changed, 2 insertions(+) -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index 008c7ae4..e507833 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -308,6 +308,27 @@ bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float as - return true; +diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +index 55f8ac7..2d5ddf2 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +@@ -491,6 +491,8 @@ void OMXPlayerAudio::Process() + void OMXPlayerAudio::Flush() + { + m_flush = true; ++ if(m_pAudioCodec) ++ m_pAudioCodec->Reset(); + m_messageQueue.Flush(); + m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1); } - -+void CGUIFontTTFBase::Begin() -+{ -+ if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin()) -+ { -+ m_vertex_count = 0; -+ } -+ // Keep track of the nested begin/end calls. -+ m_nestedBeginCount++; -+} -+ -+void CGUIFontTTFBase::End() -+{ -+ if (m_nestedBeginCount == 0) -+ return; -+ -+ if (--m_nestedBeginCount > 0) -+ return; -+ -+ LastEnd(); -+} -+ - void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling) - { - Begin(); -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index 4501dbd..df54a5d 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -77,8 +77,8 @@ class CGUIFontTTFBase - - bool Load(const CStdString& strFilename, float height = 20.0f, float aspect = 1.0f, float lineSpacing = 1.0f, bool border = false); - -- virtual void Begin() = 0; -- virtual void End() = 0; -+ void Begin(); -+ void End(); - - const CStdString& GetFileName() const { return m_strFileName; }; - -@@ -168,6 +168,8 @@ class CGUIFontTTFBase - CStdString m_strFileName; - - private: -+ virtual bool FirstBegin() = 0; -+ virtual void LastEnd() = 0; - CGUIFontTTFBase(const CGUIFontTTFBase&); - CGUIFontTTFBase& operator=(const CGUIFontTTFBase&); - int m_referenceCount; -diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp -index e3eba24..2f90668 100644 ---- a/xbmc/guilib/GUIFontTTFDX.cpp -+++ b/xbmc/guilib/GUIFontTTFDX.cpp -@@ -51,65 +51,56 @@ CGUIFontTTFDX::~CGUIFontTTFDX(void) - free(m_index); - } - --void CGUIFontTTFDX::Begin() -+bool CGUIFontTTFDX::FirstBegin() - { - LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice(); - - if (pD3DDevice == NULL) -+ { - CLog::Log(LOGERROR, __FUNCTION__" - failed to get Direct3D device"); -+ return false; -+ } - -- if (m_nestedBeginCount == 0 && pD3DDevice != NULL && m_texture != NULL) -+ int unit = 0; -+ // just have to blit from our texture. -+ m_texture->BindToUnit(unit); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); -+ unit++; -+ -+ if(g_Windowing.UseLimitedColor()) - { -- int unit = 0; -- // just have to blit from our texture. -- m_texture->BindToUnit(unit); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse -- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD ); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ; -+ pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) ); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR ); - unit++; -- -- if(g_Windowing.UseLimitedColor()) -- { -- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD ); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ; -- pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) ); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR ); -- unit++; -- } -- -- // no other texture stages needed -- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE); -- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE); -- -- pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); -- pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); -- pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); -- pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); -- pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); -- pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); -- pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); -- pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE); -- -- pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); -- m_vertex_count = 0; - } - -- // Keep track of the nested begin/end calls. -- m_nestedBeginCount++; -+ // no other texture stages needed -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE); -+ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE); -+ -+ pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); -+ pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); -+ pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); -+ pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); -+ pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); -+ pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); -+ pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); -+ pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE); -+ -+ pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); -+ return true; - } - --void CGUIFontTTFDX::End() -+void CGUIFontTTFDX::LastEnd() - { - LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice(); - -- if (m_nestedBeginCount == 0) -- return; -- -- if (--m_nestedBeginCount > 0) -- return; -- - if (m_vertex_count == 0) - return; - -diff --git a/xbmc/guilib/GUIFontTTFDX.h b/xbmc/guilib/GUIFontTTFDX.h -index 0431085..17dfefe 100644 ---- a/xbmc/guilib/GUIFontTTFDX.h -+++ b/xbmc/guilib/GUIFontTTFDX.h -@@ -41,8 +41,8 @@ class CGUIFontTTFDX : public CGUIFontTTFBase - CGUIFontTTFDX(const CStdString& strFileName); - virtual ~CGUIFontTTFDX(void); - -- virtual void Begin(); -- virtual void End(); -+ virtual bool FirstBegin(); -+ virtual void LastEnd(); - - protected: - virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index 6a8291b..97853fd 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -53,108 +53,96 @@ CGUIFontTTFGL::~CGUIFontTTFGL(void) - { - } - --void CGUIFontTTFGL::Begin() -+bool CGUIFontTTFGL::FirstBegin() - { -- if (m_nestedBeginCount == 0 && m_texture != NULL) -+ if (m_textureStatus == TEXTURE_REALLOCATED) - { -- if (m_textureStatus == TEXTURE_REALLOCATED) -- { -- if (glIsTexture(m_nTexture)) -- g_TextureManager.ReleaseHwTexture(m_nTexture); -- m_textureStatus = TEXTURE_VOID; -- } -- -- if (m_textureStatus == TEXTURE_VOID) -- { -- // Have OpenGL generate a texture object handle for us -- glGenTextures(1, (GLuint*) &m_nTexture); -+ if (glIsTexture(m_nTexture)) -+ g_TextureManager.ReleaseHwTexture(m_nTexture); -+ m_textureStatus = TEXTURE_VOID; -+ } - -- // Bind the texture object -- glBindTexture(GL_TEXTURE_2D, m_nTexture); -+ if (m_textureStatus == TEXTURE_VOID) -+ { -+ // Have OpenGL generate a texture object handle for us -+ glGenTextures(1, (GLuint*) &m_nTexture); -+ -+ // Bind the texture object -+ glBindTexture(GL_TEXTURE_2D, m_nTexture); - #ifdef HAS_GL -- glEnable(GL_TEXTURE_2D); -+ glEnable(GL_TEXTURE_2D); - #endif -- // Set the texture's stretching properties -- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -+ // Set the texture's stretching properties -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - -- // Set the texture image -- THIS WORKS, so the pixels must be wrong. -- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0, -- GL_ALPHA, GL_UNSIGNED_BYTE, 0); -- -- VerifyGLState(); -- m_textureStatus = TEXTURE_UPDATED; -- } -+ // Set the texture image -- THIS WORKS, so the pixels must be wrong. -+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0, -+ GL_ALPHA, GL_UNSIGNED_BYTE, 0); - -- if (m_textureStatus == TEXTURE_UPDATED) -- { -- glBindTexture(GL_TEXTURE_2D, m_nTexture); -- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1, GL_ALPHA, GL_UNSIGNED_BYTE, -- m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch()); -- glDisable(GL_TEXTURE_2D); -- -- m_updateY1 = m_updateY2 = 0; -- m_textureStatus = TEXTURE_READY; -- } -+ VerifyGLState(); -+ m_textureStatus = TEXTURE_UPDATED; -+ } - -- // Turn Blending On -- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); -- glEnable(GL_BLEND); -+ if (m_textureStatus == TEXTURE_UPDATED) -+ { -+ glBindTexture(GL_TEXTURE_2D, m_nTexture); -+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1, GL_ALPHA, GL_UNSIGNED_BYTE, -+ m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch()); -+ glDisable(GL_TEXTURE_2D); -+ -+ m_updateY1 = m_updateY2 = 0; -+ m_textureStatus = TEXTURE_READY; -+ } -+ -+ // Turn Blending On -+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); -+ glEnable(GL_BLEND); - #ifdef HAS_GL -- glEnable(GL_TEXTURE_2D); -+ glEnable(GL_TEXTURE_2D); - #endif -- glBindTexture(GL_TEXTURE_2D, m_nTexture); -+ glBindTexture(GL_TEXTURE_2D, m_nTexture); - - #ifdef HAS_GL -- glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); -- glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE); -- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); -- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); -- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); -- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0); -- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); -- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); -- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); -- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -- VerifyGLState(); -+ glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); -+ glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE); -+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); -+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); -+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); -+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0); -+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); -+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); -+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); -+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -+ VerifyGLState(); -+ -+ if(g_Windowing.UseLimitedColor()) -+ { -+ glActiveTexture(GL_TEXTURE1); -+ glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind -+ glEnable(GL_TEXTURE_2D); - -- if(g_Windowing.UseLimitedColor()) -- { -- glActiveTexture(GL_TEXTURE1); -- glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind -- glEnable(GL_TEXTURE_2D); -- -- const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f}; -- glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE); -- glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba); -- glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD); -- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS); -- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT); -- glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR); -- glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR); -- glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE); -- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS); -- VerifyGLState(); -- } -+ const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f}; -+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE); -+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba); -+ glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD); -+ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS); -+ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT); -+ glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR); -+ glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR); -+ glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE); -+ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS); -+ VerifyGLState(); -+ } - - #else -- g_Windowing.EnableGUIShader(SM_FONTS); -+ g_Windowing.EnableGUIShader(SM_FONTS); - #endif -- -- m_vertex_count = 0; -- } -- // Keep track of the nested begin/end calls. -- m_nestedBeginCount++; -+ return true; - } - --void CGUIFontTTFGL::End() -+void CGUIFontTTFGL::LastEnd() - { -- if (m_nestedBeginCount == 0) -- return; -- -- if (--m_nestedBeginCount > 0) -- return; -- - #ifdef HAS_GL - glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - -diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h -index c0bb53a..735fb3a 100644 ---- a/xbmc/guilib/GUIFontTTFGL.h -+++ b/xbmc/guilib/GUIFontTTFGL.h -@@ -41,8 +41,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase - CGUIFontTTFGL(const CStdString& strFileName); - virtual ~CGUIFontTTFGL(void); - -- virtual void Begin(); -- virtual void End(); -+ virtual bool FirstBegin(); -+ virtual void LastEnd(); - - protected: - virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); --- -2.0.4 +From c91dc3d4c772d38882ce2aeed58b9ce0b779cffe Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 18 Aug 2014 23:16:28 +0100 +Subject: [PATCH 02/77] [omxplayer] Don't flush queued data on general reset -From 2ae68d725f8c8a4336dc8b534c8819aac6349e2f Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 11 Dec 2013 18:47:54 +0000 -Subject: [PATCH 02/98] Convert CGUIFontTTFBase::m_vertex to be managed as a - std::vector. +We were flushing the queue of data to gpu (which can be a number of seconds worth) on a general reset. +However this is generated on inoccuous events like a chapter change in dvd playback. -Also retired CGUIFontTTFBase::m_vertex_count and -CGUIFontTTFBase::m_vertex_size because these can be derived from vector -member functions. +This results in a few seconds loss of audio, and a temporary audio/video sync error --- - xbmc/guilib/GUIFontTTF.cpp | 29 +++++------------------------ - xbmc/guilib/GUIFontTTF.h | 4 +--- - xbmc/guilib/GUIFontTTFDX.cpp | 12 ++++++------ - xbmc/guilib/GUIFontTTFGL.cpp | 12 ++++++------ - 4 files changed, 18 insertions(+), 39 deletions(-) + xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 1 - + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 1 - + 2 files changed, 2 deletions(-) -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index e507833..0a80471 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -138,8 +138,7 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) - m_maxChars = 0; - m_nestedBeginCount = 0; - -- m_vertex_size = 4*1024; -- m_vertex = (SVertex*)malloc(m_vertex_size * sizeof(SVertex)); -+ m_vertex.reserve(4*1024); - - m_face = NULL; - m_stroker = NULL; -@@ -154,7 +153,6 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) - m_textureScaleX = m_textureScaleY = 0.0; - m_ellipsesWidth = m_height = 0.0f; - m_color = 0; -- m_vertex_count = 0; - m_nTexture = 0; - } - -@@ -215,9 +213,7 @@ void CGUIFontTTFBase::Clear() - g_freeTypeLibrary.ReleaseStroker(m_stroker); - m_stroker = NULL; - -- free(m_vertex); -- m_vertex = NULL; -- m_vertex_count = 0; -+ m_vertex.clear(); - } - - bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float aspect, float lineSpacing, bool border) -@@ -312,7 +308,7 @@ void CGUIFontTTFBase::Begin() - { - if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin()) - { -- m_vertex_count = 0; -+ m_vertex.clear(); - } - // Keep track of the nested begin/end calls. - m_nestedBeginCount++; -@@ -745,22 +741,9 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c - float tt = texture.y1 * m_textureScaleY; - float tb = texture.y2 * m_textureScaleY; - -- // grow the vertex buffer if required -- if(m_vertex_count >= m_vertex_size) -- { -- m_vertex_size *= 2; -- void* old = m_vertex; -- m_vertex = (SVertex*)realloc(m_vertex, m_vertex_size * sizeof(SVertex)); -- if (!m_vertex) -- { -- free(old); -- CLog::Log(LOGSEVERE, "%s: can't allocate %" PRIdS" bytes for texture", __FUNCTION__ , m_vertex_size * sizeof(SVertex)); -- return; -- } -- } -- -+ m_vertex.resize(m_vertex.size() + 4); -+ SVertex* v = &m_vertex[m_vertex.size() - 4]; - m_color = color; -- SVertex* v = m_vertex + m_vertex_count; - - unsigned char r = GET_R(color) - , g = GET_G(color) -@@ -827,8 +810,6 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c - v[3].y = y[2]; - v[3].z = z[2]; - #endif -- -- m_vertex_count+=4; - } - - // Oblique code - original taken from freetype2 (ftsynth.c) -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index df54a5d..10a7060 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -156,9 +156,7 @@ class CGUIFontTTFBase - - unsigned int m_nTexture; - -- SVertex* m_vertex; -- int m_vertex_count; -- int m_vertex_size; -+ std::vector m_vertex; - - float m_textureScaleX; - float m_textureScaleY; -diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp -index 2f90668..6ef8984 100644 ---- a/xbmc/guilib/GUIFontTTFDX.cpp -+++ b/xbmc/guilib/GUIFontTTFDX.cpp -@@ -101,17 +101,17 @@ void CGUIFontTTFDX::LastEnd() - { - LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice(); - -- if (m_vertex_count == 0) -+ if (m_vertex.size() == 0) - return; - -- unsigned index_size = m_vertex_size * 6 / 4; -+ unsigned index_size = m_vertex.capacity() * 6 / 4; - if(m_index_size < index_size) - { - uint16_t* id = (uint16_t*)calloc(index_size, sizeof(uint16_t)); - if(id == NULL) - return; - -- for(int i = 0, b = 0; i < m_vertex_size; i += 4, b += 6) -+ for(int i = 0, b = 0; i < m_vertex.capacity(); i += 4, b += 6) - { - id[b+0] = i + 0; - id[b+1] = i + 1; -@@ -140,11 +140,11 @@ void CGUIFontTTFDX::LastEnd() - - pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST - , 0 -- , m_vertex_count -- , m_vertex_count / 2 -+ , m_vertex.size() -+ , m_vertex.size() / 2 - , m_index - , D3DFMT_INDEX16 -- , m_vertex -+ , &m_vertex[0] - , sizeof(SVertex)); - pD3DDevice->SetTransform(D3DTS_WORLD, &orig); - -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index 97853fd..b76c6a5 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -146,13 +146,13 @@ void CGUIFontTTFGL::LastEnd() - #ifdef HAS_GL - glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - -- glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r)); -- glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x)); -- glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u)); -+ glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, r)); -+ glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, x)); -+ glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, u)); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); -- glDrawArrays(GL_QUADS, 0, m_vertex_count); -+ glDrawArrays(GL_QUADS, 0, m_vertex.size()); - glPopClientAttrib(); - - glActiveTexture(GL_TEXTURE1); -@@ -168,10 +168,10 @@ void CGUIFontTTFGL::LastEnd() - GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); - - // stack object until VBOs will be used -- std::vector vecVertices( 6 * (m_vertex_count / 4) ); -+ std::vector vecVertices( 6 * (m_vertex.size() / 4) ); - SVertex *vertices = &vecVertices[0]; - -- for (int i=0; i -Date: Mon, 16 Dec 2013 18:58:12 +0000 -Subject: [PATCH 03/98] CGUIFontTTFBase::RenderCharacter can now append to - arbitrary vectors of vertices rather than only CGUIFontTTFBase::m_vertex - ---- - xbmc/guilib/GUIFontTTF.cpp | 12 +++++++----- - xbmc/guilib/GUIFontTTF.h | 2 +- - 2 files changed, 8 insertions(+), 6 deletions(-) - -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index 0a80471..848c5c8 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -329,6 +329,8 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - { - Begin(); - -+ std::vector &vertices = m_vertex; -+ - // save the origin, which is scaled separately - m_originX = x; - m_originY = y; -@@ -409,7 +411,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - - for (int i = 0; i < 3; i++) - { -- RenderCharacter(startX + cursorX, startY, period, color, !scrolling); -+ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices); - cursorX += period->advance; - } - break; -@@ -418,7 +420,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) - break; // exceeded max allowed width - stop rendering - -- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling); -+ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices); - if ( alignment & XBFONT_JUSTIFIED ) - { - if ((*pos & 0xffff) == L' ') -@@ -675,7 +677,7 @@ bool CGUIFontTTFBase::CacheCharacter(wchar_t letter, uint32_t style, Character * - return true; - } - --void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX) -+void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector &vertices) - { - // actual image width isn't same as the character width as that is - // just baseline width and height should include the descent -@@ -741,8 +743,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c - float tt = texture.y1 * m_textureScaleY; - float tb = texture.y2 * m_textureScaleY; - -- m_vertex.resize(m_vertex.size() + 4); -- SVertex* v = &m_vertex[m_vertex.size() - 4]; -+ vertices.resize(vertices.size() + 4); -+ SVertex* v = &vertices[vertices.size() - 4]; - m_color = color; - - unsigned char r = GET_R(color) -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index 10a7060..dde0350 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -109,7 +109,7 @@ class CGUIFontTTFBase - // Stuff for pre-rendering for speed - inline Character *GetCharacter(character_t letter); - bool CacheCharacter(wchar_t letter, uint32_t style, Character *ch); -- void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX); -+ void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector &vertices); - void ClearCharacterCache(); - - virtual CBaseTexture* ReallocTexture(unsigned int& newHeight) = 0; --- -2.0.4 - - -From cd87208a9b45510cae4b10fcc9bcaed8bc456d1f Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 15 Jan 2014 17:18:38 +0000 -Subject: [PATCH 04/98] Add a cache of font glyph bounding box vertices. - -This is implemented as a template because ultimately we will key on different -parameters and store values of different types, depending upon whether we -have a GLES or non-GLES backend, and for GLES, whether or not the currently -applicable transformation matrices permit the use of hardware clipping. ---- - XBMC.xcodeproj/project.pbxproj | 10 ++ - project/VS2010Express/XBMC.vcxproj | 2 + - project/VS2010Express/XBMC.vcxproj.filters | 6 + - xbmc/guilib/GUIFontCache.cpp | 105 ++++++++++++++ - xbmc/guilib/GUIFontCache.h | 217 +++++++++++++++++++++++++++++ - xbmc/guilib/GUIFontTTF.cpp | 181 +++++++++++++----------- - xbmc/guilib/GUIFontTTF.h | 5 + - xbmc/guilib/GUIFontTTFGL.cpp | 1 + - xbmc/guilib/GraphicContext.h | 1 + - xbmc/guilib/Makefile.in | 1 + - xbmc/guilib/TransformMatrix.h | 11 ++ - 11 files changed, 456 insertions(+), 84 deletions(-) - create mode 100644 xbmc/guilib/GUIFontCache.cpp - create mode 100644 xbmc/guilib/GUIFontCache.h - -diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj -index 7272e09..d4035eb 100644 ---- a/XBMC.xcodeproj/project.pbxproj -+++ b/XBMC.xcodeproj/project.pbxproj -@@ -168,6 +168,9 @@ - 1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D638126161E211E003603ED /* PeripheralImon.cpp */; }; - 1DAFDB7C16DFDCA7007F8C68 /* PeripheralBusCEC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DAFDB7A16DFDCA7007F8C68 /* PeripheralBusCEC.cpp */; }; - 1DE0443515828F4B005DDB4D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; }; -+ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; }; -+ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; }; -+ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; }; - 32C631281423A90F00F18420 /* JpegIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32C631261423A90F00F18420 /* JpegIO.cpp */; }; - 36A9443D15821E2800727135 /* DatabaseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443B15821E2800727135 /* DatabaseUtils.cpp */; }; - 36A9444115821E7C00727135 /* SortUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443F15821E7C00727135 /* SortUtils.cpp */; }; -@@ -4005,6 +4008,8 @@ - 1DAFDB7B16DFDCA7007F8C68 /* PeripheralBusCEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeripheralBusCEC.h; sourceTree = ""; }; - 1DE0443315828F4B005DDB4D /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exception.cpp; path = commons/Exception.cpp; sourceTree = ""; }; - 1DE0443415828F4B005DDB4D /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = commons/Exception.h; sourceTree = ""; }; -+ 2F4564D31970129A00396109 /* GUIFontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIFontCache.cpp; sourceTree = ""; }; -+ 2F4564D41970129A00396109 /* GUIFontCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIFontCache.h; sourceTree = ""; }; - 32C631261423A90F00F18420 /* JpegIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JpegIO.cpp; sourceTree = ""; }; - 32C631271423A90F00F18420 /* JpegIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JpegIO.h; sourceTree = ""; }; - 36A9443B15821E2800727135 /* DatabaseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseUtils.cpp; sourceTree = ""; }; -@@ -6508,6 +6513,8 @@ - 18B7C7101294222D009E7A26 /* GUIFixedListContainer.h */, - 18B7C76B1294222E009E7A26 /* GUIFont.cpp */, - 18B7C7111294222D009E7A26 /* GUIFont.h */, -+ 2F4564D31970129A00396109 /* GUIFontCache.cpp */, -+ 2F4564D41970129A00396109 /* GUIFontCache.h */, - 18B7C76C1294222E009E7A26 /* GUIFontManager.cpp */, - 18B7C7121294222D009E7A26 /* GUIFontManager.h */, - 18B7C76D1294222E009E7A26 /* GUIFontTTF.cpp */, -@@ -10984,6 +10991,7 @@ - 7C5608C70F1754930056433A /* ExternalPlayer.cpp in Sources */, - F584E12E0F257C5100DB26A5 /* HTTPDirectory.cpp in Sources */, - F54C51D20F1E783200D46E3C /* GUIDialogKaraokeSongSelector.cpp in Sources */, -+ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */, - F54C51D50F1E784800D46E3C /* karaokelyricscdg.cpp in Sources */, - F54C51D80F1E785700D46E3C /* karaokelyrics.cpp in Sources */, - F54C51E50F1E787700D46E3C /* karaokelyricstextkar.cpp in Sources */, -@@ -12649,6 +12657,7 @@ - DFF0F45B17528350002DA3A4 /* Control.cpp in Sources */, - DFF0F45C17528350002DA3A4 /* Dialog.cpp in Sources */, - DFF0F45D17528350002DA3A4 /* File.cpp in Sources */, -+ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */, - DFF0F45E17528350002DA3A4 /* InfoTagMusic.cpp in Sources */, - DFF0F45F17528350002DA3A4 /* InfoTagVideo.cpp in Sources */, - DFF0F46017528350002DA3A4 /* Keyboard.cpp in Sources */, -@@ -13447,6 +13456,7 @@ - E499131D174E5DAD00741B6D /* GUIVisualisationControl.cpp in Sources */, - E499131E174E5DAD00741B6D /* GUIWindow.cpp in Sources */, - E499131F174E5DAD00741B6D /* GUIWindowManager.cpp in Sources */, -+ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */, - E4991320174E5DAD00741B6D /* GUIWrappingListContainer.cpp in Sources */, - E4991321174E5DAD00741B6D /* imagefactory.cpp in Sources */, - E4991322174E5DAD00741B6D /* IWindowManagerCallback.cpp in Sources */, -diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj -index e5b6e16..68f10ad 100644 ---- a/project/VS2010Express/XBMC.vcxproj -+++ b/project/VS2010Express/XBMC.vcxproj -@@ -425,6 +425,7 @@ - - - -+ - - - -@@ -1740,6 +1741,7 @@ - - - -+ - - - -diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters -index 6469841..ab1085e 100644 ---- a/project/VS2010Express/XBMC.vcxproj.filters -+++ b/project/VS2010Express/XBMC.vcxproj.filters -@@ -988,6 +988,9 @@ - - guilib - -+ -+ guilib -+ - - guilib - -@@ -3873,6 +3876,9 @@ - - guilib - -+ -+ guilib -+ - - guilib - -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp -new file mode 100644 -index 0000000..2c72f9c ---- /dev/null -+++ b/xbmc/guilib/GUIFontCache.cpp -@@ -0,0 +1,105 @@ -+/* -+ * Copyright (C) 2005-2013 Team XBMC -+ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include -+#include -+#include "utils/StdString.h" // required by GUIFontTTF.h -+#include "GUIFontTTF.h" -+#include "GraphicContext.h" -+ -+template -+void CGUIFontCacheEntry::Reassign::operator()(CGUIFontCacheEntry &entry) -+{ -+ entry.m_key.m_pos = m_key.m_pos; -+ entry.m_key.m_colors.assign(m_key.m_colors.begin(), m_key.m_colors.end()); -+ entry.m_key.m_text.assign(m_key.m_text.begin(), m_key.m_text.end()); -+ entry.m_key.m_alignment = m_key.m_alignment; -+ entry.m_key.m_maxPixelWidth = m_key.m_maxPixelWidth; -+ entry.m_key.m_scrolling = m_key.m_scrolling; -+ entry.m_matrix = m_key.m_matrix; -+ entry.m_key.m_scaleX = m_key.m_scaleX; -+ entry.m_key.m_scaleY = m_key.m_scaleY; -+ -+ entry.m_lastUsedMillis = m_nowMillis; -+ entry.m_value.clear(); -+} -+ -+template -+CGUIFontCacheEntry::~CGUIFontCacheEntry() -+{ -+ delete &m_key.m_colors; -+ delete &m_key.m_text; -+ m_value.clear(); -+} -+ -+template -+Value &CGUIFontCache::Lookup(Position &pos, -+ const vecColors &colors, const vecText &text, -+ uint32_t alignment, float maxPixelWidth, -+ bool scrolling, -+ unsigned int nowMillis, bool &dirtyCache) -+{ -+ const CGUIFontCacheKey key(pos, -+ const_cast(colors), const_cast(text), -+ alignment, maxPixelWidth, -+ scrolling, g_graphicsContext.GetGUIMatrix(), -+ g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY()); -+ EntryHashIterator i = m_list.template get().find(key); -+ if (i == m_list.template get().end()) -+ { -+ /* Cache miss */ -+ EntryAgeIterator oldest = m_list.template get().begin(); -+ if (!m_list.template get().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT) -+ { -+ /* The oldest existing entry is old enough to expire and reuse */ -+ m_list.template get().modify(m_list.template project(oldest), typename CGUIFontCacheEntry::Reassign(key, nowMillis)); -+ m_list.template get().relocate(m_list.template get().end(), oldest); -+ } -+ else -+ { -+ /* We need a new entry instead */ -+ /* Yes, this causes the creation an destruction of a temporary entry, but -+ * this code ought to only be used infrequently, when the cache needs to grow */ -+ m_list.template get().push_back(CGUIFontCacheEntry(*this, key, nowMillis)); -+ } -+ dirtyCache = true; -+ return (--m_list.template get().end())->m_value; -+ } -+ else -+ { -+ /* Cache hit */ -+ /* Update time in entry and move to the back of the list */ -+ i->m_lastUsedMillis = nowMillis; -+ m_list.template get().relocate(m_list.template get().end(), m_list.template project(i)); -+ dirtyCache = false; -+ return i->m_value; -+ } -+} -+ -+template -+void CGUIFontCache::Flush() -+{ -+ m_list.template get().clear(); -+} -+ -+template void CGUIFontCacheEntry::Reassign::operator()(CGUIFontCacheEntry &entry); -+template CGUIFontCacheEntry::~CGUIFontCacheEntry(); -+template CGUIFontCacheStaticValue &CGUIFontCache::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); -+template void CGUIFontCache::Flush(); -diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h -new file mode 100644 -index 0000000..ef65845 ---- /dev/null -+++ b/xbmc/guilib/GUIFontCache.h -@@ -0,0 +1,217 @@ -+/*! -+\file GUIFontCache.h -+\brief -+*/ -+ -+#ifndef CGUILIB_GUIFONTCACHE_H -+#define CGUILIB_GUIFONTCACHE_H -+#pragma once -+ -+/* -+ * Copyright (C) 2005-2013 Team XBMC -+ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "boost/multi_index_container.hpp" -+#include "boost/multi_index/sequenced_index.hpp" -+#include "boost/multi_index/hashed_index.hpp" -+#include "boost/multi_index/member.hpp" -+ -+#include "TransformMatrix.h" -+ -+using namespace boost::multi_index; -+ -+#define FONT_CACHE_TIME_LIMIT (1000) -+ -+template class CGUIFontCache; -+class CGUIFontTTFBase; -+ -+template -+struct CGUIFontCacheKey -+{ -+ Position m_pos; -+ vecColors &m_colors; -+ vecText &m_text; -+ uint32_t m_alignment; -+ float m_maxPixelWidth; -+ bool m_scrolling; -+ const TransformMatrix &m_matrix; -+ float m_scaleX; -+ float m_scaleY; -+ -+ CGUIFontCacheKey(Position pos, -+ vecColors &colors, vecText &text, -+ uint32_t alignment, float maxPixelWidth, -+ bool scrolling, const TransformMatrix &matrix, -+ float scaleX, float scaleY) : -+ m_pos(pos), -+ m_colors(colors), m_text(text), -+ m_alignment(alignment), m_maxPixelWidth(maxPixelWidth), -+ m_scrolling(scrolling), m_matrix(matrix), -+ m_scaleX(scaleX), m_scaleY(scaleY) -+ {} -+}; -+ -+template -+struct CGUIFontCacheEntry -+{ -+ const CGUIFontCache &m_cache; -+ CGUIFontCacheKey m_key; -+ TransformMatrix m_matrix; -+ -+ /* These need to be declared as mutable to get round the fact that only -+ * const iterators are available. These fields do not affect comparison or -+ * hash functors, so from the container's point of view, they are mutable. */ -+ mutable unsigned int m_lastUsedMillis; -+ mutable Value m_value; -+ -+ CGUIFontCacheEntry(const CGUIFontCache &cache, const CGUIFontCacheKey &key, unsigned int nowMillis) : -+ m_cache(cache), -+ m_key(key.m_pos, -+ *new vecColors, *new vecText, -+ key.m_alignment, key.m_maxPixelWidth, -+ key.m_scrolling, m_matrix, -+ key.m_scaleX, key.m_scaleY), -+ m_lastUsedMillis(nowMillis) -+ { -+ m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end()); -+ m_key.m_text.assign(key.m_text.begin(), key.m_text.end()); -+ m_matrix = key.m_matrix; -+ } -+ -+ CGUIFontCacheEntry(const CGUIFontCacheEntry &other) : -+ m_cache(other.m_cache), -+ m_key(other.m_key.m_pos, -+ *new vecColors, *new vecText, -+ other.m_key.m_alignment, other.m_key.m_maxPixelWidth, -+ other.m_key.m_scrolling, m_matrix, -+ other.m_key.m_scaleX, other.m_key.m_scaleY), -+ m_lastUsedMillis(other.m_lastUsedMillis), -+ m_value(other.m_value) -+ { -+ m_key.m_colors.assign(other.m_key.m_colors.begin(), other.m_key.m_colors.end()); -+ m_key.m_text.assign(other.m_key.m_text.begin(), other.m_key.m_text.end()); -+ m_matrix = other.m_key.m_matrix; -+ } -+ -+ struct Reassign -+ { -+ Reassign(const CGUIFontCacheKey &key, unsigned int nowMillis) : m_key(key), m_nowMillis(nowMillis) {} -+ void operator()(CGUIFontCacheEntry &entry); -+ private: -+ const CGUIFontCacheKey &m_key; -+ unsigned int m_nowMillis; -+ }; -+ -+ ~CGUIFontCacheEntry(); -+}; -+ -+template -+struct CGUIFontCacheHash -+{ -+ size_t operator()(const CGUIFontCacheKey &key) const -+ { -+ /* Not much effort has gone into choosing this hash function */ -+ size_t hash = 0, i; -+ for (i = 0; i < 3 && i < key.m_text.size(); ++i) -+ hash += key.m_text[i]; -+ if (key.m_colors.size()) -+ hash += key.m_colors[0]; -+ hash += MatrixHashContribution(key); -+ return hash; -+ } -+}; -+ -+template -+struct CGUIFontCacheKeysMatch -+{ -+ bool operator()(const CGUIFontCacheKey &a, const CGUIFontCacheKey &b) const -+ { -+ return a.m_text == b.m_text && -+ a.m_colors == b.m_colors && -+ a.m_alignment == b.m_alignment && -+ a.m_scrolling == b.m_scrolling && -+ a.m_maxPixelWidth == b.m_maxPixelWidth && -+ Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) && -+ a.m_scaleX == b.m_scaleX && -+ a.m_scaleY == b.m_scaleY; -+ } -+}; -+ -+template -+class CGUIFontCache -+{ -+ /* Empty structs used as tags to identify indexes */ -+ struct Age {}; -+ struct Hash {}; -+ -+ typedef multi_index_container< -+ CGUIFontCacheEntry, -+ indexed_by< -+ sequenced >, -+ hashed_unique, member, CGUIFontCacheKey, &CGUIFontCacheEntry::m_key>, CGUIFontCacheHash, CGUIFontCacheKeysMatch > -+ > -+ > EntryList; -+ -+ typedef typename EntryList::template index::type::iterator EntryAgeIterator; -+ typedef typename EntryList::template index::type::iterator EntryHashIterator; -+ -+ EntryList m_list; -+ -+public: -+ const CGUIFontTTFBase &m_font; -+ -+ CGUIFontCache(CGUIFontTTFBase &font) : m_font(font) {} -+ Value &Lookup(Position &pos, -+ const vecColors &colors, const vecText &text, -+ uint32_t alignment, float maxPixelWidth, -+ bool scrolling, -+ unsigned int nowMillis, bool &dirtyCache); -+ void Flush(); -+}; -+ -+struct CGUIFontCacheStaticPosition -+{ -+ float m_x; -+ float m_y; -+ CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {} -+}; -+ -+typedef std::vector CGUIFontCacheStaticValue; -+ -+inline bool Match(const CGUIFontCacheStaticPosition &a, const TransformMatrix &a_m, -+ const CGUIFontCacheStaticPosition &b, const TransformMatrix &b_m, -+ bool scrolling) -+{ -+ return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m; -+} -+ -+inline float MatrixHashContribution(const CGUIFontCacheKey &a) -+{ -+ /* Ensure horizontally translated versions end up in different buckets */ -+ return a.m_matrix.m[0][3]; -+} -+ -+#endif -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index 848c5c8..0290fc4 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -27,6 +27,7 @@ - #include "utils/MathUtils.h" - #include "utils/log.h" - #include "windowing/WindowingFactory.h" -+#include "threads/SystemClock.h" - - #include - -@@ -131,7 +132,7 @@ class CFreeTypeLibrary - XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library - #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary) - --CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) -+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this) - { - m_texture = NULL; - m_char = NULL; -@@ -329,108 +330,120 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - { - Begin(); - -- std::vector &vertices = m_vertex; -- -- // save the origin, which is scaled separately -- m_originX = x; -- m_originY = y; -- -- // Check if we will really need to truncate or justify the text -- if ( alignment & XBFONT_TRUNCATED ) -+ bool dirtyCache; -+ CGUIFontCacheStaticPosition staticPos(x, y); -+ std::vector &vertices = m_staticCache.Lookup(staticPos, -+ colors, text, -+ alignment, maxPixelWidth, -+ scrolling, -+ XbmcThreads::SystemClockMillis(), -+ dirtyCache); -+ if (dirtyCache) - { -- if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth) -- alignment &= ~XBFONT_TRUNCATED; -- } -- else if ( alignment & XBFONT_JUSTIFIED ) -- { -- if ( maxPixelWidth <= 0.0f ) -- alignment &= ~XBFONT_JUSTIFIED; -- } -+ // save the origin, which is scaled separately -+ m_originX = x; -+ m_originY = y; - -- // calculate sizing information -- float startX = 0; -- float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering -+ // Check if we will really need to truncate or justify the text -+ if ( alignment & XBFONT_TRUNCATED ) -+ { -+ if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth) -+ alignment &= ~XBFONT_TRUNCATED; -+ } -+ else if ( alignment & XBFONT_JUSTIFIED ) -+ { -+ if ( maxPixelWidth <= 0.0f ) -+ alignment &= ~XBFONT_JUSTIFIED; -+ } - -- if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) ) -- { -- // Get the extent of this line -- float w = GetTextWidthInternal( text.begin(), text.end() ); -+ // calculate sizing information -+ float startX = 0; -+ float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering - -- if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues -- w = maxPixelWidth; -+ if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) ) -+ { -+ // Get the extent of this line -+ float w = GetTextWidthInternal( text.begin(), text.end() ); - -- if ( alignment & XBFONT_CENTER_X) -- w *= 0.5f; -- // Offset this line's starting position -- startX -= w; -- } -+ if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues -+ w = maxPixelWidth; - -- float spacePerLetter = 0; // for justification effects -- if ( alignment & XBFONT_JUSTIFIED ) -- { -- // first compute the size of the text to render in both characters and pixels -- unsigned int lineChars = 0; -- float linePixels = 0; -- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) -+ if ( alignment & XBFONT_CENTER_X) -+ w *= 0.5f; -+ // Offset this line's starting position -+ startX -= w; -+ } -+ -+ float spacePerLetter = 0; // for justification effects -+ if ( alignment & XBFONT_JUSTIFIED ) - { -- Character *ch = GetCharacter(*pos); -- if (ch) -- { // spaces have multiple times the justification spacing of normal letters -- lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1; -- linePixels += ch->advance; -+ // first compute the size of the text to render in both characters and pixels -+ unsigned int lineChars = 0; -+ float linePixels = 0; -+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) -+ { -+ Character *ch = GetCharacter(*pos); -+ if (ch) -+ { // spaces have multiple times the justification spacing of normal letters -+ lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1; -+ linePixels += ch->advance; -+ } - } -+ if (lineChars > 1) -+ spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1); +diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +index 2d5ddf2..01d2afc 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp +@@ -403,7 +403,6 @@ void OMXPlayerAudio::Process() + CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET"); + if (m_pAudioCodec) + m_pAudioCodec->Reset(); +- m_omxAudio.Flush(); + m_started = false; + m_audioClock = DVD_NOPTS_VALUE; } -- if (lineChars > 1) -- spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1); -- } -- float cursorX = 0; // current position along the line -- -- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) -- { -- // If starting text on a new line, determine justification effects -- // Get the current letter in the CStdString -- color_t color = (*pos & 0xff0000) >> 16; -- if (color >= colors.size()) -- color = 0; -- color = colors[color]; -+ float cursorX = 0; // current position along the line - -- // grab the next character -- Character *ch = GetCharacter(*pos); -- if (!ch) continue; -- -- if ( alignment & XBFONT_TRUNCATED ) -+ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index 7a30c6c..2c25fd9 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -391,7 +391,6 @@ void OMXPlayerVideo::Process() + else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) { -- // Check if we will be exceeded the max allowed width -- if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth ) -- { -- // Yup. Let's draw the ellipses, then bail -- // Perhaps we should really bail to the next line in this case?? -- Character *period = GetCharacter(L'.'); -- if (!period) -- break; -+ // If starting text on a new line, determine justification effects -+ // Get the current letter in the CStdString -+ color_t color = (*pos & 0xff0000) >> 16; -+ if (color >= colors.size()) -+ color = 0; -+ color = colors[color]; -+ -+ // grab the next character -+ Character *ch = GetCharacter(*pos); -+ if (!ch) continue; - -- for (int i = 0; i < 3; i++) -+ if ( alignment & XBFONT_TRUNCATED ) -+ { -+ // Check if we will be exceeded the max allowed width -+ if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth ) - { -- RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices); -- cursorX += period->advance; -+ // Yup. Let's draw the ellipses, then bail -+ // Perhaps we should really bail to the next line in this case?? -+ Character *period = GetCharacter(L'.'); -+ if (!period) -+ break; -+ -+ for (int i = 0; i < 3; i++) -+ { -+ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices); -+ cursorX += period->advance; -+ } -+ break; - } -- break; - } -- } -- else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) -- break; // exceeded max allowed width - stop rendering -+ else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) -+ break; // exceeded max allowed width - stop rendering - -- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices); -- if ( alignment & XBFONT_JUSTIFIED ) -- { -- if ((*pos & 0xffff) == L' ') -- cursorX += ch->advance + spacePerLetter * justification_word_weight; -+ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices); -+ if ( alignment & XBFONT_JUSTIFIED ) -+ { -+ if ((*pos & 0xffff) == L' ') -+ cursorX += ch->advance + spacePerLetter * justification_word_weight; -+ else -+ cursorX += ch->advance + spacePerLetter; -+ } - else -- cursorX += ch->advance + spacePerLetter; -+ cursorX += ch->advance; - } -- else -- cursorX += ch->advance; - } -+ /* Append the new vertices (from the cache or otherwise) to the set collected -+ * since the first Begin() call */ -+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); - - End(); - } -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index dde0350..77111bc 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -64,6 +64,9 @@ struct SVertex - }; - - -+#include "GUIFontCache.h" -+ -+ - class CGUIFontTTFBase - { - friend class CGUIFont; -@@ -165,6 +168,8 @@ class CGUIFontTTFBase - - CStdString m_strFileName; - -+ CGUIFontCache m_staticCache; -+ - private: - virtual bool FirstBegin() = 0; - virtual void LastEnd() = 0; -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index b76c6a5..9935ea4 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -221,6 +221,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) - m_textureScaleX = 1.0f / m_textureWidth; - if (m_textureHeight < newHeight) - CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight); -+ m_staticCache.Flush(); - - memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch()); - if (m_texture) -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h -index 6c2dcd4..bab2457 100644 ---- a/xbmc/guilib/GraphicContext.h -+++ b/xbmc/guilib/GraphicContext.h -@@ -146,6 +146,7 @@ class CGraphicContext : public CCriticalSection, - inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.matrix.TransformPosition(x, y, z); } - bool RectIsAngled(float x1, float y1, float x2, float y2) const; - -+ inline const TransformMatrix &GetGUIMatrix() const XBMC_FORCE_INLINE { return m_finalTransform.matrix; } - inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_finalTransform.scaleX; } - inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_finalTransform.scaleY; } - inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE -diff --git a/xbmc/guilib/Makefile.in b/xbmc/guilib/Makefile.in -index 086fb0d..af82979 100644 ---- a/xbmc/guilib/Makefile.in -+++ b/xbmc/guilib/Makefile.in -@@ -23,6 +23,7 @@ SRCS += GUIEditControl.cpp - SRCS += GUIFadeLabelControl.cpp - SRCS += GUIFixedListContainer.cpp - SRCS += GUIFont.cpp -+SRCS += GUIFontCache.cpp - SRCS += GUIFontManager.cpp - SRCS += GUIFontTTF.cpp - SRCS += GUIImage.cpp -diff --git a/xbmc/guilib/TransformMatrix.h b/xbmc/guilib/TransformMatrix.h -index f351c99..9036ba9 100644 ---- a/xbmc/guilib/TransformMatrix.h -+++ b/xbmc/guilib/TransformMatrix.h -@@ -245,3 +245,14 @@ class TransformMatrix - float alpha; - bool identity; - }; -+ -+inline bool operator==(const TransformMatrix &a, const TransformMatrix &b) -+{ -+ return a.alpha == b.alpha && ((a.identity && b.identity) || -+ (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof a.m / sizeof a.m[0][0], &b.m[0][0]))); -+} -+ -+inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b) -+{ -+ return !operator==(a, b); -+} --- -2.0.4 + CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET"); +- m_omxVideo.Reset(); + m_started = false; + m_nextOverlay = DVD_NOPTS_VALUE; + m_iCurrentPts = DVD_NOPTS_VALUE; +From 05e74bdeac984a465a5a132f127ea60c0aa2a773 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 30 Dec 2013 12:02:14 +0000 +Subject: [PATCH 03/77] [rbp] Hardware accelerated resampling -From fd9954757fcc329a0520b49d2dcc40e6b6bfd268 Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Thu, 23 Jan 2014 22:24:17 +0000 -Subject: [PATCH 05/98] Lay the groundwork for hardware clipping. +This replaces the format conversion, up/down mixing and resampling code from ActiveAE with a GPU accelerated version. +Should significantly reduce CPU when using paplayer or dvdplayer. -For glScissor() to replace CGraphicContext::ClipRect, a necessary condition -is that no shear or rotation is introduced between the coordinate systems -they use; this depends upon the settings of the GUI matrix m_finalTransform -as well as the OpenGL model-view and projection matrices. These all remain -unchanged between paired calls of CGUIShader::OnEnabled and -CGUIShader::OnDisabled, so we scan the matrices in CGUIShader::OnEnabled to -see whether hardware clipping is possible. - -Then, in CGUIFontTTFBase::RenderCharacter, we don't apply software clipping -in such cases. However, because vertices arising from multiple -CGUIFontTTFBase::DrawTextInternal calls (each of which often uses a different -clip rectangle) get lumped into the same vector, which only at the end is -passed to OpenGL for rendering, we need to wait a few commits before we can -actually apply hardware clipping. In the meantime, expect to see rendering -errors. +Requires updated firmware --- - xbmc/guilib/GUIFontTTF.cpp | 3 +- - xbmc/guilib/GUIShader.cpp | 80 +++++++++++++++++++++++++++++++- - xbmc/guilib/GUIShader.h | 11 +++++ - xbmc/guilib/GraphicContext.cpp | 10 ++++ - xbmc/guilib/GraphicContext.h | 1 + - xbmc/rendering/RenderSystem.h | 2 + - xbmc/rendering/gles/RenderSystemGLES.cpp | 22 +++++++++ - xbmc/rendering/gles/RenderSystemGLES.h | 2 + - 8 files changed, 128 insertions(+), 3 deletions(-) + .../Engines/ActiveAE/ActiveAEResample.cpp | 5 + + .../Engines/ActiveAE/ActiveAEResample.h | 8 + + .../Engines/ActiveAE/ActiveAEResamplePi.cpp | 656 +++++++++++++++++++++ + .../Engines/ActiveAE/ActiveAEResamplePi.h | 63 ++ + xbmc/cores/AudioEngine/Makefile.in | 1 + + xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 14 +- + xbmc/linux/OMXCore.cpp | 4 +- + 7 files changed, 742 insertions(+), 9 deletions(-) + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index 0290fc4..e3808d9 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -709,7 +709,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c - (posY + ch->offsetY + height) * g_graphicsContext.GetGUIScaleY()); - vertex += CPoint(m_originX, m_originY); - CRect texture(ch->left, ch->top, ch->right, ch->bottom); -- g_graphicsContext.ClipRect(vertex, texture); -+ if (!g_Windowing.ScissorsCanEffectClipping()) -+ g_graphicsContext.ClipRect(vertex, texture); - - // transform our positions - note, no scaling due to GUI calibration/resolution occurs - float x[4], y[4], z[4]; -diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp -index 23cb84f..5d836cee 100644 ---- a/xbmc/guilib/GUIShader.cpp -+++ b/xbmc/guilib/GUIShader.cpp -@@ -26,6 +26,8 @@ - #include "GUIShader.h" - #include "MatrixGLES.h" - #include "utils/log.h" -+#include "windowing/WindowingFactory.h" -+#include "guilib/GraphicContext.h" - - using namespace Shaders; - -@@ -88,8 +90,82 @@ bool CGUIShader::OnEnabled() - { - // This is called after glUseProgram() - -- glUniformMatrix4fv(m_hProj, 1, GL_FALSE, g_matrices.GetMatrix(MM_PROJECTION)); -- glUniformMatrix4fv(m_hModel, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); -+ GLfloat *projMatrix = g_matrices.GetMatrix(MM_PROJECTION); -+ GLfloat *modelMatrix = g_matrices.GetMatrix(MM_MODELVIEW); -+ glUniformMatrix4fv(m_hProj, 1, GL_FALSE, projMatrix); -+ glUniformMatrix4fv(m_hModel, 1, GL_FALSE, modelMatrix); -+ -+ const TransformMatrix &guiMatrix = g_graphicsContext.GetGUIMatrix(); -+ CRect viewPort; // absolute positions of corners -+ g_Windowing.GetViewPort(viewPort); -+ -+ /* glScissor operates in window coordinates. In order that we can use it to -+ * perform clipping, we must ensure that there is an independent linear -+ * transformation from the coordinate system used by CGraphicContext::ClipRect -+ * to window coordinates, separately for X and Y (in other words, no -+ * rotation or shear is introduced at any stage). To do, this, we need to -+ * check that zeros are present in the following locations: -+ * -+ * GUI matrix: -+ * / * 0 * * \ -+ * | 0 * * * | -+ * \ 0 0 * * / -+ * ^ TransformMatrix::TransformX/Y/ZCoord are only ever called with -+ * input z = 0, so this column doesn't matter -+ * Model-view matrix: -+ * / * 0 0 * \ -+ * | 0 * 0 * | -+ * | 0 0 * * | -+ * \ * * * * / <- eye w has no influence on window x/y (last column below -+ * is either 0 or ignored) -+ * Projection matrix: -+ * / * 0 0 0 \ -+ * | 0 * 0 0 | -+ * | * * * * | <- normalised device coordinate z has no influence on window x/y -+ * \ 0 0 * 0 / -+ * -+ * Some of these zeros are not strictly required to ensure this, but they tend -+ * to be zeroed in the common case, so by checking for zeros here, we simplify -+ * the calculation of the window x/y coordinates further down the line. -+ * -+ * (Minor detail: we don't quite deal in window coordinates as defined by -+ * OpenGL, because CRenderSystemGLES::SetScissors flips the Y axis. But all -+ * that's needed to handle that is an effective negation at the stage where -+ * Y is in normalised device coordinates.) -+ */ -+ m_clipPossible = guiMatrix.m[0][1] == 0 && -+ guiMatrix.m[1][0] == 0 && -+ guiMatrix.m[2][0] == 0 && -+ guiMatrix.m[2][1] == 0 && -+ modelMatrix[0+1*4] == 0 && -+ modelMatrix[0+2*4] == 0 && -+ modelMatrix[1+0*4] == 0 && -+ modelMatrix[1+2*4] == 0 && -+ modelMatrix[2+0*4] == 0 && -+ modelMatrix[2+1*4] == 0 && -+ projMatrix[0+1*4] == 0 && -+ projMatrix[0+2*4] == 0 && -+ projMatrix[0+3*4] == 0 && -+ projMatrix[1+0*4] == 0 && -+ projMatrix[1+2*4] == 0 && -+ projMatrix[1+3*4] == 0 && -+ projMatrix[3+0*4] == 0 && -+ projMatrix[3+1*4] == 0 && -+ projMatrix[3+3*4] == 0; -+ if (m_clipPossible) -+ { -+ m_clipXFactor = guiMatrix.m[0][0] * modelMatrix[0+0*4] * projMatrix[0+0*4]; -+ m_clipXOffset = (guiMatrix.m[0][3] * modelMatrix[0+0*4] + modelMatrix[0+3*4]) * projMatrix[0+0*4]; -+ m_clipYFactor = guiMatrix.m[1][1] * modelMatrix[1+1*4] * projMatrix[1+1*4]; -+ m_clipYOffset = (guiMatrix.m[1][3] * modelMatrix[1+1*4] + modelMatrix[1+3*4]) * projMatrix[1+1*4]; -+ float clipW = (guiMatrix.m[2][3] * modelMatrix[2+2*4] + modelMatrix[2+3*4]) * projMatrix[3+2*4]; -+ float xMult = (viewPort.x2 - viewPort.x1) / (2 * clipW); -+ float yMult = (viewPort.y1 - viewPort.y2) / (2 * clipW); // correct for inverted window coordinate scheme -+ m_clipXFactor = m_clipXFactor * xMult; -+ m_clipXOffset = m_clipXOffset * xMult + (viewPort.x2 + viewPort.x1) / 2; -+ m_clipYFactor = m_clipYFactor * yMult; -+ m_clipYOffset = m_clipYOffset * yMult + (viewPort.y2 + viewPort.y1) / 2; -+ } - - return true; - } -diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h -index f7b5d9a..fdf7452 100644 ---- a/xbmc/guilib/GUIShader.h -+++ b/xbmc/guilib/GUIShader.h -@@ -39,6 +39,11 @@ class CGUIShader : public Shaders::CGLSLShaderProgram - GLint GetCord1Loc() { return m_hCord1; } - GLint GetUniColLoc() { return m_hUniCol; } - GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; } -+ bool HardwareClipIsPossible() { return m_clipPossible; } -+ GLfloat GetClipXFactor() { return m_clipXFactor; } -+ GLfloat GetClipXOffset() { return m_clipXOffset; } -+ GLfloat GetClipYFactor() { return m_clipYFactor; } -+ GLfloat GetClipYOffset() { return m_clipYOffset; } - - protected: - GLint m_hTex0; -@@ -54,6 +59,12 @@ class CGUIShader : public Shaders::CGLSLShaderProgram - - GLfloat *m_proj; - GLfloat *m_model; -+ -+ bool m_clipPossible; -+ GLfloat m_clipXFactor; -+ GLfloat m_clipXOffset; -+ GLfloat m_clipYFactor; -+ GLfloat m_clipYOffset; - }; - - #endif // GUI_SHADER_H -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp -index 38f17a7..5bffdf5 100644 ---- a/xbmc/guilib/GraphicContext.cpp -+++ b/xbmc/guilib/GraphicContext.cpp -@@ -167,6 +167,16 @@ void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2) - } - } - -+CRect CGraphicContext::GetClipRegion() -+{ -+ if (m_clipRegions.empty()) -+ return CRect(0, 0, m_iScreenWidth, m_iScreenHeight); -+ CRect clipRegion(m_clipRegions.top()); -+ if (!m_origins.empty()) -+ clipRegion -= m_origins.top(); -+ return clipRegion; -+} -+ - bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */) - { - // transform coordinates - we may have a rotation which changes the positioning of the -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h -index bab2457..0a27643 100644 ---- a/xbmc/guilib/GraphicContext.h -+++ b/xbmc/guilib/GraphicContext.h -@@ -199,6 +199,7 @@ class CGraphicContext : public CCriticalSection, - void ApplyHardwareTransform(); - void RestoreHardwareTransform(); - void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL); -+ CRect GetClipRegion(); - inline void AddGUITransform() - { - m_transforms.push(m_finalTransform); -diff --git a/xbmc/rendering/RenderSystem.h b/xbmc/rendering/RenderSystem.h -index fa64eba..c1dfb93 100644 ---- a/xbmc/rendering/RenderSystem.h -+++ b/xbmc/rendering/RenderSystem.h -@@ -110,6 +110,8 @@ class CRenderSystemBase - virtual void GetViewPort(CRect& viewPort) = 0; - virtual void RestoreViewPort() {}; - -+ virtual bool ScissorsCanEffectClipping() { return false; } -+ virtual CRect ClipRectToScissorRect(const CRect &rect) { return CRect(); } - virtual void SetScissors(const CRect &rect) = 0; - virtual void ResetScissors() = 0; - -diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp -index 653c9ec..deb3afc 100644 ---- a/xbmc/rendering/gles/RenderSystemGLES.cpp -+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp -@@ -533,6 +533,28 @@ void CRenderSystemGLES::SetViewPort(CRect& viewPort) - m_viewPort[3] = viewPort.Height(); - } - -+bool CRenderSystemGLES::ScissorsCanEffectClipping() -+{ -+ if (m_pGUIshader[m_method]) -+ return m_pGUIshader[m_method]->HardwareClipIsPossible(); -+ -+ return false; -+} -+ -+CRect CRenderSystemGLES::ClipRectToScissorRect(const CRect &rect) -+{ -+ if (!m_pGUIshader[m_method]) -+ return CRect(); -+ float xFactor = m_pGUIshader[m_method]->GetClipXFactor(); -+ float xOffset = m_pGUIshader[m_method]->GetClipXOffset(); -+ float yFactor = m_pGUIshader[m_method]->GetClipYFactor(); -+ float yOffset = m_pGUIshader[m_method]->GetClipYOffset(); -+ return CRect(rect.x1 * xFactor + xOffset, -+ rect.y1 * yFactor + yOffset, -+ rect.x2 * xFactor + xOffset, -+ rect.y2 * yFactor + yOffset); -+} -+ - void CRenderSystemGLES::SetScissors(const CRect &rect) - { - if (!m_bRenderCreated) -diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h -index 98e398a..81ee49e 100644 ---- a/xbmc/rendering/gles/RenderSystemGLES.h -+++ b/xbmc/rendering/gles/RenderSystemGLES.h -@@ -63,6 +63,8 @@ class CRenderSystemGLES : public CRenderSystemBase - virtual void SetViewPort(CRect& viewPort); - virtual void GetViewPort(CRect& viewPort); - -+ virtual bool ScissorsCanEffectClipping(); -+ virtual CRect ClipRectToScissorRect(const CRect &rect); - virtual void SetScissors(const CRect& rect); - virtual void ResetScissors(); - --- -2.0.4 - - -From 1034dc69ccf5224f3dc09daf6c3bcf6fa44436cc Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Thu, 23 Jan 2014 16:42:22 +0000 -Subject: [PATCH 06/98] Increase font cache hit rate by keying on the - fractional part of m_originX and m_originY *after* they have been through the - graphics context's transformation matrix, plus the scale/rotation elements of - the matrix, rather than the origin in the original frame of reference plus - the complete transformation matrix. All vertices of individual glyph bounding - boxes are a constant offset from this position, and when the fractional part - of the translation is a match, the rounding of each vertex will be in the - same direction; this permits us to calculate the desired vertices from the - cached ones simply by adding the integer parts of the translations with no - additional rounding steps. - -Note that this requires that software clipping is *not* performed. ---- - xbmc/guilib/GUIFontCache.cpp | 8 +++++++ - xbmc/guilib/GUIFontCache.h | 43 +++++++++++++++++++++++++++++++++++ - xbmc/guilib/GUIFontTTF.cpp | 53 +++++++++++++++++++++++++++++++++++--------- - xbmc/guilib/GUIFontTTF.h | 1 + - 4 files changed, 95 insertions(+), 10 deletions(-) - -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp -index 2c72f9c..df466a5 100644 ---- a/xbmc/guilib/GUIFontCache.cpp -+++ b/xbmc/guilib/GUIFontCache.cpp -@@ -85,6 +85,9 @@ Value &CGUIFontCache::Lookup(Position &pos, - else - { - /* Cache hit */ -+ /* Update the translation arguments so that they hold the offset to apply -+ * to the cached values (but only in the dynamic case) */ -+ pos.UpdateWithOffsets(i->m_key.m_pos, scrolling); - /* Update time in entry and move to the back of the list */ - i->m_lastUsedMillis = nowMillis; - m_list.template get().relocate(m_list.template get().end(), m_list.template project(i)); -@@ -103,3 +106,8 @@ template void CGUIFontCacheEntry::~CGUIFontCacheEntry(); - template CGUIFontCacheStaticValue &CGUIFontCache::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); - template void CGUIFontCache::Flush(); -+ -+template void CGUIFontCacheEntry::Reassign::operator()(CGUIFontCacheEntry &entry); -+template CGUIFontCacheEntry::~CGUIFontCacheEntry(); -+template CGUIFontCacheDynamicValue &CGUIFontCache::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); -+template void CGUIFontCache::Flush(); -diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h -index ef65845..d913dee 100644 ---- a/xbmc/guilib/GUIFontCache.h -+++ b/xbmc/guilib/GUIFontCache.h -@@ -44,6 +44,7 @@ - using namespace boost::multi_index; - - #define FONT_CACHE_TIME_LIMIT (1000) -+#define FONT_CACHE_DIST_LIMIT (0.01) - - template class CGUIFontCache; - class CGUIFontTTFBase; -@@ -197,6 +198,7 @@ struct CGUIFontCacheStaticPosition - float m_x; - float m_y; - CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {} -+ void UpdateWithOffsets(const CGUIFontCacheStaticPosition &cached, bool scrolling) {} - }; - - typedef std::vector CGUIFontCacheStaticValue; -@@ -214,4 +216,45 @@ inline float MatrixHashContribution(const CGUIFontCacheKey CGUIFontCacheDynamicValue; -+ -+inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m, -+ const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m, -+ bool scrolling) -+{ -+ float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT; -+ float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT; -+ float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT; -+ return (scrolling || diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) && -+ diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT && -+ diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT && -+ a_m.m[0][0] == b_m.m[0][0] && -+ a_m.m[1][1] == b_m.m[1][1] && -+ a_m.m[2][2] == b_m.m[2][2]; -+ // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements -+} -+ -+inline float MatrixHashContribution(const CGUIFontCacheKey &a) -+{ -+ return 0; -+} -+ - #endif -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index e3808d9..412f47a 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -132,7 +132,7 @@ class CFreeTypeLibrary - XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library - #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary) - --CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this) -+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this), m_dynamicCache(*this) - { - m_texture = NULL; - m_char = NULL; -@@ -331,13 +331,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - Begin(); - - bool dirtyCache; -+ bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping(); - CGUIFontCacheStaticPosition staticPos(x, y); -- std::vector &vertices = m_staticCache.Lookup(staticPos, -- colors, text, -- alignment, maxPixelWidth, -- scrolling, -- XbmcThreads::SystemClockMillis(), -- dirtyCache); -+ CGUIFontCacheDynamicPosition dynamicPos; -+ if (hardwareClipping) -+ { -+ dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y), -+ g_graphicsContext.ScaleFinalYCoord(x, y), -+ g_graphicsContext.ScaleFinalZCoord(x, y)); -+ } -+ std::vector &vertices = hardwareClipping ? -+ m_dynamicCache.Lookup(dynamicPos, -+ colors, text, -+ alignment, maxPixelWidth, -+ scrolling, -+ XbmcThreads::SystemClockMillis(), -+ dirtyCache) : -+ m_staticCache.Lookup(staticPos, -+ colors, text, -+ alignment, maxPixelWidth, -+ scrolling, -+ XbmcThreads::SystemClockMillis(), -+ dirtyCache); - if (dirtyCache) - { - // save the origin, which is scaled separately -@@ -440,10 +455,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - else - cursorX += ch->advance; - } -+ if (hardwareClipping) -+ /* Append the new vertices (which we have just constructed in the cache) -+ * to the set collected since the first Begin() call */ -+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); -+ } -+ else if (hardwareClipping) -+ { -+ /* Apply the translation offset to the vertices from the cache after -+ * appending them to the set collected since the first Begin() call */ -+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); -+ SVertex *v; -+ for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++) -+ { -+ v->x += dynamicPos.m_x; -+ v->y += dynamicPos.m_y; -+ v->z += dynamicPos.m_z; -+ } - } -- /* Append the new vertices (from the cache or otherwise) to the set collected -- * since the first Begin() call */ -- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); -+ if (!hardwareClipping) -+ /* Append the new vertices (from the cache or otherwise) to the set collected -+ * since the first Begin() call */ -+ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); - - End(); - } -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index 77111bc..39bfa52 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -169,6 +169,7 @@ class CGUIFontTTFBase - CStdString m_strFileName; - - CGUIFontCache m_staticCache; -+ CGUIFontCache m_dynamicCache; - - private: - virtual bool FirstBegin() = 0; --- -2.0.4 - - -From c3134f6882e448a9d8bb9bfed9cd95ee6a4984f6 Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 8 Jan 2014 12:16:33 +0000 -Subject: [PATCH 07/98] Rewrite of scrolling text code. - -No longer shuffles the string round to minimise the number of characters -before the clipping rectangle; this doesn't save much on rendering time but -does harm the effectiveness of the cache. Now uses a pixel offset into the -string rather than a character + pixel offset, and plots the entire string -every time (execpt when the wrap point is visible, in which case the entire -string is plotted twice). - -It also makes motion smoother, because (possibly unintentionally) the -previous code preferred to align the scroll offset with character boundaries. -This would lead to uneven changes of position, especially when the width of -the character currently being scrolled off the edge was only slightly more -than an integral multiple of the scroll increment. ---- - xbmc/guilib/GUIFadeLabelControl.cpp | 8 +-- - xbmc/guilib/GUIFont.cpp | 123 +++++++++++++----------------------- - xbmc/guilib/GUIFont.h | 17 ++--- - xbmc/guilib/GUIRSSControl.cpp | 6 +- - xbmc/utils/RssReader.cpp | 2 +- - xbmc/utils/RssReader.h | 2 +- - 6 files changed, 58 insertions(+), 100 deletions(-) - -diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp -index 844f960..5859d9f 100644 ---- a/xbmc/guilib/GUIFadeLabelControl.cpp -+++ b/xbmc/guilib/GUIFadeLabelControl.cpp -@@ -109,18 +109,14 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d - bool moveToNextLabel = false; - if (!m_scrollOut) - { -- vecText text; -- m_textLayout.GetFirstText(text); -- if (m_scrollInfo.characterPos && m_scrollInfo.characterPos < text.size()) -- text.erase(text.begin(), text.begin() + min((int)m_scrollInfo.characterPos - 1, (int)text.size())); -- if (m_label.font->GetTextWidth(text) < m_width) -+ if (m_scrollInfo.pixelPos + m_width > m_scrollInfo.m_textWidth) - { - if (m_fadeAnim.GetProcess() != ANIM_PROCESS_NORMAL) - m_fadeAnim.QueueAnimation(ANIM_PROCESS_NORMAL); - moveToNextLabel = true; - } - } -- else if (m_scrollInfo.characterPos > m_textLayout.GetTextLength()) -+ else if (m_scrollInfo.pixelPos > m_scrollInfo.m_textWidth) - moveToNextLabel = true; - - // apply the fading animation -diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp -index a7ee668..eb8efdb 100644 ---- a/xbmc/guilib/GUIFont.cpp -+++ b/xbmc/guilib/GUIFont.cpp -@@ -36,7 +36,12 @@ CScrollInfo::CScrollInfo(unsigned int wait /* = 50 */, float pos /* = 0 */, - initialWait = wait; - initialPos = pos; - SetSpeed(speed ? speed : defaultSpeed); -- g_charsetConverter.utf8ToW(scrollSuffix, suffix); -+ CStdStringW wsuffix; -+ g_charsetConverter.utf8ToW(scrollSuffix, wsuffix); -+ suffix.clear(); -+ suffix.reserve(wsuffix.size()); -+ for (vecText::size_type i = 0; i < wsuffix.size(); i++) -+ suffix.push_back(wsuffix[i]); - Reset(); - } - -@@ -115,11 +120,12 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo) - { - // draw at our scroll position - // we handle the scrolling as follows: -- // We scroll on a per-pixel basis up until we have scrolled the first character outside -- // of our viewport, whereby we cycle the string around, and reset the scroll position. -- // -- // pixelPos is the amount in pixels to move the string by. -- // characterPos is the amount in characters to rotate the string by. -+ // We scroll on a per-pixel basis (eschewing the use of character indices -+ // which were also in use previously). The complete string, including suffix, -+ // is plotted to achieve the desired effect - normally just the one time, but -+ // if there is a wrap point within the viewport then it will be plotted twice. -+ // If the string is smaller than the viewport, then it may be plotted even -+ // more times than that. - // - if (scrollInfo.waitTime) - { -@@ -135,54 +141,19 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo) - // move along by the appropriate scroll amount - float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX()); - -- if (scrollInfo.pixelSpeed > 0) -+ if (!scrollInfo.m_widthValid) - { -- // we want to move scrollAmount, grab the next character -- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); -- if (scrollInfo.pixelPos + scrollAmount < charWidth) -- scrollInfo.pixelPos += scrollAmount; // within the current character -- else -- { // past the current character, decrement scrollAmount by the charWidth and move to the next character -- while (scrollInfo.pixelPos + scrollAmount >= charWidth) -- { -- scrollAmount -= (charWidth - scrollInfo.pixelPos); -- scrollInfo.pixelPos = 0; -- scrollInfo.characterPos++; -- if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size()) -- { -- scrollInfo.Reset(); -- break; -- } -- charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); -- } -- } -- } -- else if (scrollInfo.pixelSpeed < 0) -- { // scrolling backwards -- // we want to move scrollAmount, grab the next character -- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); -- if (scrollInfo.pixelPos + scrollAmount < charWidth) -- scrollInfo.pixelPos += scrollAmount; // within the current character -- else -- { // past the current character, decrement scrollAmount by the charWidth and move to the next character -- while (scrollInfo.pixelPos + scrollAmount >= charWidth) -- { -- scrollAmount -= (charWidth - scrollInfo.pixelPos); -- scrollInfo.pixelPos = 0; -- if (scrollInfo.characterPos == 0) -- { -- scrollInfo.Reset(); -- scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1; -- break; -- } -- scrollInfo.characterPos--; -- charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); -- } -- } -+ /* Calculate the pixel width of the complete string */ -+ scrollInfo.m_textWidth = GetTextWidth(text); -+ scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix); -+ scrollInfo.m_widthValid = true; - } -+ scrollInfo.pixelPos += scrollAmount; -+ assert(scrollInfo.m_totalWidth != 0); -+ while (scrollInfo.pixelPos >= scrollInfo.m_totalWidth) -+ scrollInfo.pixelPos -= scrollInfo.m_totalWidth; - -- if(scrollInfo.characterPos != old.characterPos -- || scrollInfo.pixelPos != old.pixelPos) -+ if (scrollInfo.pixelPos != old.pixelPos) - return true; - else - return false; -@@ -194,39 +165,27 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo - if (!m_font) return; - if (!shadowColor) shadowColor = m_shadowColor; - -- float spaceWidth = GetCharWidth(L' '); -- // max chars on screen + extra margin chars -- vecText::size_type maxChars = -- std::min( -- (text.size() + (vecText::size_type)scrollInfo.suffix.size()), -- (vecText::size_type)((maxWidth * 1.05f) / spaceWidth)); -- - if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment)) - return; // nothing to render - -- maxWidth = ROUND((maxWidth + scrollInfo.pixelPos) / g_graphicsContext.GetGUIScaleX()); -+ if (!scrollInfo.m_widthValid) -+ { -+ /* Calculate the pixel width of the complete string */ -+ scrollInfo.m_textWidth = GetTextWidth(text); -+ scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix); -+ scrollInfo.m_widthValid = true; -+ } -+ -+ assert(scrollInfo.m_totalWidth != 0); -+ -+ float textPixelWidth = ROUND(scrollInfo.m_textWidth / g_graphicsContext.GetGUIScaleX()); -+ float suffixPixelWidth = ROUND((scrollInfo.m_totalWidth - scrollInfo.m_textWidth) / g_graphicsContext.GetGUIScaleX()); - -- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); - float offset; - if(scrollInfo.pixelSpeed >= 0) - offset = scrollInfo.pixelPos; - else -- offset = charWidth - scrollInfo.pixelPos; -- -- // Now rotate our string as needed, only take a slightly larger then visible part of the text. -- unsigned int pos = scrollInfo.characterPos; -- vecText renderText; -- renderText.reserve(maxChars); -- for (vecText::size_type i = 0; i < maxChars; i++) -- { -- if (pos >= text.size() + scrollInfo.suffix.size()) -- pos = 0; -- if (pos < text.size()) -- renderText.push_back(text[pos]); -- else -- renderText.push_back(scrollInfo.suffix[pos - text.size()]); -- pos++; -- } -+ offset = scrollInfo.m_totalWidth - scrollInfo.pixelPos; - - vecColors renderColors; - for (unsigned int i = 0; i < colors.size(); i++) -@@ -239,9 +198,17 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo - vecColors shadowColors; - for (unsigned int i = 0; i < renderColors.size(); i++) - shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0); -- m_font->DrawTextInternal(x - offset + 1, y + 1, shadowColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll); -+ for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth) -+ { -+ m_font->DrawTextInternal(x + dx + 1, y + 1, shadowColors, text, alignment, textPixelWidth, scroll); -+ m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll); -+ } -+ } -+ for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth) -+ { -+ m_font->DrawTextInternal(x + dx, y, renderColors, text, alignment, textPixelWidth, scroll); -+ m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth, y, renderColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll); - } -- m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll); - - g_graphicsContext.RestoreClipRegion(); - } -diff --git a/xbmc/guilib/GUIFont.h b/xbmc/guilib/GUIFont.h -index c55db48..09cf9b3 100644 ---- a/xbmc/guilib/GUIFont.h -+++ b/xbmc/guilib/GUIFont.h -@@ -64,7 +64,6 @@ class CScrollInfo - void Reset() - { - waitTime = initialWait; -- characterPos = 0; - // pixelPos is where we start the current letter, so is measured - // to the left of the text rendering's left edge. Thus, a negative - // value will mean the text starts to the right -@@ -72,25 +71,19 @@ class CScrollInfo - // privates: - m_averageFrameTime = 1000.f / abs(defaultSpeed); - m_lastFrameTime = 0; -- } -- uint32_t GetCurrentChar(const vecText &text) const -- { -- assert(text.size()); -- if (characterPos < text.size()) -- return text[characterPos]; -- else if (characterPos < text.size() + suffix.size()) -- return suffix[characterPos - text.size()]; -- return text[0]; -+ m_widthValid = false; - } - float GetPixelsPerFrame(); - - float pixelPos; - float pixelSpeed; - unsigned int waitTime; -- unsigned int characterPos; - unsigned int initialWait; - float initialPos; -- CStdStringW suffix; -+ vecText suffix; -+ mutable float m_textWidth; -+ mutable float m_totalWidth; -+ mutable bool m_widthValid; - - static const int defaultSpeed = 60; - private: -diff --git a/xbmc/guilib/GUIRSSControl.cpp b/xbmc/guilib/GUIRSSControl.cpp -index 8d985cf..a8e20fc 100644 ---- a/xbmc/guilib/GUIRSSControl.cpp -+++ b/xbmc/guilib/GUIRSSControl.cpp -@@ -119,7 +119,9 @@ void CGUIRSSControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyre - dirty = true; - - if (CRssManager::Get().GetReader(GetID(), GetParentID(), this, m_pReader)) -- m_scrollInfo.characterPos = m_pReader->m_SavedScrollPos; -+ { -+ m_scrollInfo.pixelPos = m_pReader->m_savedScrollPixelPos; -+ } - else - { - if (m_strRSSTags != "") -@@ -174,7 +176,7 @@ void CGUIRSSControl::Render() - if (m_pReader) - { - m_pReader->CheckForUpdates(); -- m_pReader->m_SavedScrollPos = m_scrollInfo.characterPos; -+ m_pReader->m_savedScrollPixelPos = m_scrollInfo.pixelPos; - } - } - CGUIControl::Render(); -diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp -index 5383156..41f9bc2 100644 ---- a/xbmc/utils/RssReader.cpp -+++ b/xbmc/utils/RssReader.cpp -@@ -55,7 +55,7 @@ CRssReader::CRssReader() : CThread("RSSReader") - m_pObserver = NULL; - m_spacesBetweenFeeds = 0; - m_bIsRunning = false; -- m_SavedScrollPos = 0; -+ m_savedScrollPixelPos = 0; - m_rtlText = false; - m_requestRefresh = false; - } -diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h -index 2cda726..fbc579e 100644 ---- a/xbmc/utils/RssReader.h -+++ b/xbmc/utils/RssReader.h -@@ -43,7 +43,7 @@ class CRssReader : public CThread - void SetObserver(IRssObserver* observer); - void CheckForUpdates(); - void requestRefresh(); -- unsigned int m_SavedScrollPos; -+ float m_savedScrollPixelPos; - - private: - void Process(); --- -2.0.4 - - -From f36c2de11f14d7968c661f9fcd985872564ffd1c Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Mon, 27 Jan 2014 23:21:10 +0000 -Subject: [PATCH 08/98] Move the application of the translation offsets into - the GLES code. - -Still all pure software at this stage. Main change is in the data types at -the interface between CGUIFontTTFBase and CGUIFontTTFGL. The old way -(array of vertices in m_vertex) are retained in addition, for the sake`of -cases that need to use software clipping on GLES, as well as for DX and GL -support where the new scheme is not (yet?) used. ---- - xbmc/guilib/GUIFontTTF.cpp | 19 +++--------- - xbmc/guilib/GUIFontTTF.h | 17 +++++++++++ - xbmc/guilib/GUIFontTTFGL.cpp | 72 ++++++++++++++++++++++++++++++++------------ - 3 files changed, 73 insertions(+), 35 deletions(-) - -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index 412f47a..b0e69c0 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -214,6 +214,7 @@ void CGUIFontTTFBase::Clear() - g_freeTypeLibrary.ReleaseStroker(m_stroker); - m_stroker = NULL; - -+ m_vertexTrans.clear(); - m_vertex.clear(); - } - -@@ -309,6 +310,7 @@ void CGUIFontTTFBase::Begin() - { - if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin()) - { -+ m_vertexTrans.clear(); - m_vertex.clear(); - } - // Keep track of the nested begin/end calls. -@@ -456,23 +458,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - cursorX += ch->advance; - } - if (hardwareClipping) -- /* Append the new vertices (which we have just constructed in the cache) -- * to the set collected since the first Begin() call */ -- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); -+ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices)); - } - else if (hardwareClipping) -- { -- /* Apply the translation offset to the vertices from the cache after -- * appending them to the set collected since the first Begin() call */ -- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); -- SVertex *v; -- for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++) -- { -- v->x += dynamicPos.m_x; -- v->y += dynamicPos.m_y; -- v->z += dynamicPos.m_z; -- } -- } -+ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices)); - if (!hardwareClipping) - /* Append the new vertices (from the cache or otherwise) to the set collected - * since the first Begin() call */ -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index 39bfa52..e8afc1c 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -61,6 +61,14 @@ struct SVertex - unsigned char r, g, b, a; - #endif - float u, v; -+ struct SVertex Offset(float translate[3]) const -+ { -+ SVertex out = *this; -+ out.x += translate[0]; -+ out.y += translate[1]; -+ out.z += translate[2]; -+ return out; -+ } - }; - - -@@ -159,6 +167,15 @@ class CGUIFontTTFBase - - unsigned int m_nTexture; - -+ struct CTranslatedVertices -+ { -+ float translateX; -+ float translateY; -+ float translateZ; -+ const std::vector *vertexBuffer; -+ CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {} -+ }; -+ std::vector m_vertexTrans; - std::vector m_vertex; - - float m_textureScaleX; -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index 9935ea4..18c9358 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -167,34 +167,65 @@ void CGUIFontTTFGL::LastEnd() - GLint colLoc = g_Windowing.GUIShaderGetCol(); - GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); - -- // stack object until VBOs will be used -- std::vector vecVertices( 6 * (m_vertex.size() / 4) ); -- SVertex *vertices = &vecVertices[0]; -+ // Enable the attributes used by this shader -+ glEnableVertexAttribArray(posLoc); -+ glEnableVertexAttribArray(colLoc); -+ glEnableVertexAttribArray(tex0Loc); - -- for (size_t i=0; i 0) - { -- *vertices++ = m_vertex[i]; -- *vertices++ = m_vertex[i+1]; -- *vertices++ = m_vertex[i+2]; -+ // Deal with vertices that had to use software clipping -+ std::vector vecVertices( 6 * (m_vertex.size() / 4) ); -+ SVertex *vertices = &vecVertices[0]; - -- *vertices++ = m_vertex[i+1]; -- *vertices++ = m_vertex[i+3]; -- *vertices++ = m_vertex[i+2]; -- } -+ for (size_t i=0; i 0) -+ { -+ // Deal with the vertices that can be hardware clipped and therefore translated -+ std::vector vecVertices; -+ for (size_t i = 0; i < m_vertexTrans.size(); i++) -+ { -+ float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ }; -+ for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4) -+ { -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate)); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate)); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); -+ } -+ } -+ SVertex *vertices = &vecVertices[0]; - -- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); -+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); -+ // Normalize color values. Does not affect Performance at all. -+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); -+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); -+ -+ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); -+ } - -+ // Disable the attributes used by this shader - glDisableVertexAttribArray(posLoc); - glDisableVertexAttribArray(colLoc); - glDisableVertexAttribArray(tex0Loc); -@@ -222,6 +253,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) - if (m_textureHeight < newHeight) - CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight); - m_staticCache.Flush(); -+ m_dynamicCache.Flush(); - - memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch()); - if (m_texture) --- -2.0.4 - - -From 85c802291c55ce74402ed9b918346ab0706acb56 Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 15 Jan 2014 15:28:06 +0000 -Subject: [PATCH 09/98] Rather than applying the translation offsets to the - vertices, now applies them to the model view matrix from the top of the - matrix stack and pushes it over to OpenGL. The vertices themselves are still - all held client-side. - ---- - xbmc/guilib/GUIFontTTF.h | 8 ------- - xbmc/guilib/GUIFontTTFGL.cpp | 40 +++++++++++++++++++++----------- - xbmc/guilib/GUIShader.h | 1 + - xbmc/rendering/gles/RenderSystemGLES.cpp | 8 +++++++ - xbmc/rendering/gles/RenderSystemGLES.h | 1 + - 5 files changed, 36 insertions(+), 22 deletions(-) - -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index e8afc1c..573039d 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -61,14 +61,6 @@ struct SVertex - unsigned char r, g, b, a; - #endif - float u, v; -- struct SVertex Offset(float translate[3]) const -- { -- SVertex out = *this; -- out.x += translate[0]; -- out.y += translate[1]; -- out.z += translate[2]; -- return out; -- } - }; - - -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index 18c9358..ea08bf4 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -29,6 +29,7 @@ - #include "utils/log.h" - #include "utils/GLUtils.h" - #include "windowing/WindowingFactory.h" -+#include "guilib/MatrixGLES.h" - - // stuff for freetype - #include -@@ -166,6 +167,7 @@ void CGUIFontTTFGL::LastEnd() - GLint posLoc = g_Windowing.GUIShaderGetPos(); - GLint colLoc = g_Windowing.GUIShaderGetCol(); - GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); -+ GLint modelLoc = g_Windowing.GUIShaderGetModel(); - - // Enable the attributes used by this shader - glEnableVertexAttribArray(posLoc); -@@ -204,25 +206,35 @@ void CGUIFontTTFGL::LastEnd() - std::vector vecVertices; - for (size_t i = 0; i < m_vertexTrans.size(); i++) - { -- float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ }; -+ // Apply the translation to the currently active (top-of-stack) model view matrix -+ g_matrices.MatrixMode(MM_MODELVIEW); -+ g_matrices.PushMatrix(); -+ g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ); -+ glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); -+ -+ vecVertices.clear(); - for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4) - { -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate)); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate)); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]); -+ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); - } -- } -- SVertex *vertices = &vecVertices[0]; -+ SVertex *vertices = &vecVertices[0]; - -- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); -- // Normalize color values. Does not affect Performance at all. -- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); -- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); -+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); -+ // Normalize color values. Does not affect Performance at all. -+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); -+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); - -- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); -+ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); -+ -+ g_matrices.PopMatrix(); -+ } -+ // Restore the original model view matrix -+ glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); - } - - // Disable the attributes used by this shader -diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h -index fdf7452..abbe21c 100644 ---- a/xbmc/guilib/GUIShader.h -+++ b/xbmc/guilib/GUIShader.h -@@ -39,6 +39,7 @@ class CGUIShader : public Shaders::CGLSLShaderProgram - GLint GetCord1Loc() { return m_hCord1; } - GLint GetUniColLoc() { return m_hUniCol; } - GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; } -+ GLint GetModelLoc() { return m_hModel; } - bool HardwareClipIsPossible() { return m_clipPossible; } - GLfloat GetClipXFactor() { return m_clipXFactor; } - GLfloat GetClipXOffset() { return m_clipXOffset; } -diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp -index deb3afc..0904d1f 100644 ---- a/xbmc/rendering/gles/RenderSystemGLES.cpp -+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp -@@ -691,4 +691,12 @@ bool CRenderSystemGLES::SupportsStereo(RENDER_STEREO_MODE mode) - } - } - -+GLint CRenderSystemGLES::GUIShaderGetModel() -+{ -+ if (m_pGUIshader[m_method]) -+ return m_pGUIshader[m_method]->GetModelLoc(); -+ -+ return -1; -+} -+ - #endif -diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h -index 81ee49e..d2f9cd1 100644 ---- a/xbmc/rendering/gles/RenderSystemGLES.h -+++ b/xbmc/rendering/gles/RenderSystemGLES.h -@@ -91,6 +91,7 @@ class CRenderSystemGLES : public CRenderSystemBase - GLint GUIShaderGetCoord1(); - GLint GUIShaderGetUniCol(); - GLint GUIShaderGetCoord0Matrix(); -+ GLint GUIShaderGetModel(); - - protected: - virtual void SetVSyncImpl(bool enable) = 0; --- -2.0.4 - - -From e604a57c55282b322fe787be62ee450130c01ac0 Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 29 Jan 2014 13:21:19 +0000 -Subject: [PATCH 10/98] Enable hardware clipping. - ---- - xbmc/guilib/GUIFontTTF.cpp | 4 ++-- - xbmc/guilib/GUIFontTTF.h | 5 ++++- - xbmc/guilib/GUIFontTTFGL.cpp | 6 ++++++ - 3 files changed, 12 insertions(+), 3 deletions(-) - -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index b0e69c0..3ea1051 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -458,10 +458,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - cursorX += ch->advance; - } - if (hardwareClipping) -- m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices)); -+ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion())); - } - else if (hardwareClipping) -- m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices)); -+ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion())); - if (!hardwareClipping) - /* Append the new vertices (from the cache or otherwise) to the set collected - * since the first Begin() call */ -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index 573039d..a6931c1 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -27,6 +27,8 @@ +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +index cbb6d69..99cd607 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +@@ -18,6 +18,10 @@ * */ -+#include "Geometry.h" -+ - // forward definition - class CBaseTexture; - -@@ -165,7 +167,8 @@ class CGUIFontTTFBase - float translateY; - float translateZ; - const std::vector *vertexBuffer; -- CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {} -+ CRect clip; -+ CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {} - }; - std::vector m_vertexTrans; - std::vector m_vertex; -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index ea08bf4..b63e337 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -206,6 +206,10 @@ void CGUIFontTTFGL::LastEnd() - std::vector vecVertices; - for (size_t i = 0; i < m_vertexTrans.size(); i++) - { -+ // Apply the clip rectangle -+ CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip); -+ g_Windowing.SetScissors(clip); -+ - // Apply the translation to the currently active (top-of-stack) model view matrix - g_matrices.MatrixMode(MM_MODELVIEW); - g_matrices.PushMatrix(); -@@ -233,6 +237,8 @@ void CGUIFontTTFGL::LastEnd() - - g_matrices.PopMatrix(); - } -+ // Restore the original scissor rectangle -+ g_Windowing.ResetScissors(); - // Restore the original model view matrix - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); - } --- -2.0.4 - - -From 326a6f64ac8e0a10bfa0026b16c9a2dce410ca8b Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 15 Jan 2014 15:32:51 +0000 -Subject: [PATCH 11/98] Move the vertex data across to a vertex buffer object - just prior to drawing. - ---- - xbmc/guilib/GUIFontTTFGL.cpp | 24 +++++++++++++++++++----- - 1 file changed, 19 insertions(+), 5 deletions(-) - -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index b63e337..b00055d 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -228,12 +228,24 @@ void CGUIFontTTFGL::LastEnd() - } - SVertex *vertices = &vecVertices[0]; - -- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); -- // Normalize color values. Does not affect Performance at all. -- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); -- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); -- -+ // Generate a unique buffer object name and put it in vertexBuffer -+ GLuint vertexBuffer; -+ glGenBuffers(1, &vertexBuffer); -+ // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point -+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); -+ // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER -+ // binding point (i.e. our buffer object) and initialise it from the -+ // specified client-side pointer -+ glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW); -+ // Set up the offsets of the various vertex attributes within the buffer -+ // object bound to GL_ARRAY_BUFFER -+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x)); -+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r)); -+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u)); -+ // Do the actual drawing operation, using the full set of vertices in the buffer - glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); -+ // Release the buffer name for reuse -+ glDeleteBuffers(1, &vertexBuffer); - - g_matrices.PopMatrix(); - } -@@ -241,6 +253,8 @@ void CGUIFontTTFGL::LastEnd() - g_Windowing.ResetScissors(); - // Restore the original model view matrix - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); -+ // Unbind GL_ARRAY_BUFFER -+ glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - // Disable the attributes used by this shader --- -2.0.4 - - -From 01769d973a2455e1c2624dad906180d5f82cbfab Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Wed, 15 Jan 2014 16:04:04 +0000 -Subject: [PATCH 12/98] Move vertex data into an OpenGL VBO when the font cache - entry is populated. - -The font cache now stores the "name" (handle) of the VBO, rather than a vector -of vertices. ---- - xbmc/guilib/GUIFontCache.cpp | 6 ++++ - xbmc/guilib/GUIFontCache.h | 30 +++++++++++++++++- - xbmc/guilib/GUIFontTTF.cpp | 15 +++++++-- - xbmc/guilib/GUIFontTTF.h | 7 +++-- - xbmc/guilib/GUIFontTTFGL.cpp | 74 ++++++++++++++++++++++++++++++-------------- - xbmc/guilib/GUIFontTTFGL.h | 5 +++ - 6 files changed, 107 insertions(+), 30 deletions(-) - -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp -index df466a5..bd84b9a 100644 ---- a/xbmc/guilib/GUIFontCache.cpp -+++ b/xbmc/guilib/GUIFontCache.cpp -@@ -111,3 +111,9 @@ template void CGUIFontCacheEntry::~CGUIFontCacheEntry(); - template CGUIFontCacheDynamicValue &CGUIFontCache::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); - template void CGUIFontCache::Flush(); -+ -+void CVertexBuffer::clear() -+{ -+ if (m_font != NULL) -+ m_font->DestroyVertexBuffer(*this); -+} -diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h -index d913dee..ff766bf 100644 ---- a/xbmc/guilib/GUIFontCache.h -+++ b/xbmc/guilib/GUIFontCache.h -@@ -234,7 +234,35 @@ struct CGUIFontCacheDynamicPosition - } - }; - --typedef std::vector CGUIFontCacheDynamicValue; -+struct CVertexBuffer -+{ -+ void *bufferHandle; -+ size_t size; -+ CVertexBuffer() : bufferHandle(NULL), size(0), m_font(NULL) {} -+ CVertexBuffer(void *bufferHandle, size_t size, const CGUIFontTTFBase *font) : bufferHandle(bufferHandle), size(size), m_font(font) {} -+ CVertexBuffer(const CVertexBuffer &other) : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font) -+ { -+ /* In practice, the copy constructor is only called before a vertex buffer -+ * has been attached. If this should ever change, we'll need another support -+ * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */ -+ assert(other.bufferHandle == 0); -+ } -+ CVertexBuffer &operator=(CVertexBuffer &other) -+ { -+ /* This is used with move-assignment semantics for initialising the object in the font cache */ -+ assert(bufferHandle == 0); -+ bufferHandle = other.bufferHandle; -+ other.bufferHandle = 0; -+ size = other.size; -+ m_font = other.m_font; -+ return *this; -+ } -+ void clear(); -+private: -+ const CGUIFontTTFBase *m_font; -+}; -+ -+typedef CVertexBuffer CGUIFontCacheDynamicValue; - - inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m, - const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m, -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp -index 3ea1051..ea510f4 100644 ---- a/xbmc/guilib/GUIFontTTF.cpp -+++ b/xbmc/guilib/GUIFontTTF.cpp -@@ -342,13 +342,18 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - g_graphicsContext.ScaleFinalYCoord(x, y), - g_graphicsContext.ScaleFinalZCoord(x, y)); - } -- std::vector &vertices = hardwareClipping ? -+ CVertexBuffer unusedVertexBuffer; -+ CVertexBuffer &vertexBuffer = hardwareClipping ? - m_dynamicCache.Lookup(dynamicPos, - colors, text, - alignment, maxPixelWidth, - scrolling, - XbmcThreads::SystemClockMillis(), - dirtyCache) : -+ unusedVertexBuffer; -+ std::vector tempVertices; -+ std::vector &vertices = hardwareClipping ? -+ tempVertices : - m_staticCache.Lookup(staticPos, - colors, text, - alignment, maxPixelWidth, -@@ -458,10 +463,14 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors - cursorX += ch->advance; - } - if (hardwareClipping) -- m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion())); -+ { -+ CVertexBuffer newVertexBuffer = CreateVertexBuffer(tempVertices); -+ vertexBuffer = newVertexBuffer; -+ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion())); -+ } - } - else if (hardwareClipping) -- m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion())); -+ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, g_graphicsContext.GetClipRegion())); - if (!hardwareClipping) - /* Append the new vertices (from the cache or otherwise) to the set collected - * since the first Begin() call */ -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h -index a6931c1..9a35ac4 100644 ---- a/xbmc/guilib/GUIFontTTF.h -+++ b/xbmc/guilib/GUIFontTTF.h -@@ -84,6 +84,9 @@ class CGUIFontTTFBase - - void Begin(); - void End(); -+ /* The next two should only be called if we've declared we can do hardware clipping */ -+ virtual CVertexBuffer CreateVertexBuffer(const std::vector &vertices) const { assert(false); return CVertexBuffer(); } -+ virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const {} - - const CStdString& GetFileName() const { return m_strFileName; }; - -@@ -166,9 +169,9 @@ class CGUIFontTTFBase - float translateX; - float translateY; - float translateZ; -- const std::vector *vertexBuffer; -+ const CVertexBuffer *vertexBuffer; - CRect clip; -- CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {} -+ CTranslatedVertices(float translateX, float translateY, float translateZ, const CVertexBuffer *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {} - }; - std::vector m_vertexTrans; - std::vector m_vertex; -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index b00055d..aabb9a6 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -52,6 +52,10 @@ CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName) - - CGUIFontTTFGL::~CGUIFontTTFGL(void) - { -+ // It's important that all the CGUIFontCacheEntry objects are -+ // destructed before the CGUIFontTTFGL goes out of scope, because -+ // our virtual methods won't be accessible after this point -+ m_dynamicCache.Flush(); - } - - bool CGUIFontTTFGL::FirstBegin() -@@ -203,7 +207,6 @@ void CGUIFontTTFGL::LastEnd() - if (m_vertexTrans.size() > 0) - { - // Deal with the vertices that can be hardware clipped and therefore translated -- std::vector vecVertices; - for (size_t i = 0; i < m_vertexTrans.size(); i++) - { - // Apply the clip rectangle -@@ -216,36 +219,17 @@ void CGUIFontTTFGL::LastEnd() - g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); - -- vecVertices.clear(); -- for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4) -- { -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]); -- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); -- } -- SVertex *vertices = &vecVertices[0]; -- -- // Generate a unique buffer object name and put it in vertexBuffer -- GLuint vertexBuffer; -- glGenBuffers(1, &vertexBuffer); - // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point -- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); -- // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER -- // binding point (i.e. our buffer object) and initialise it from the -- // specified client-side pointer -- glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW); -+ glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle); -+ - // Set up the offsets of the various vertex attributes within the buffer - // object bound to GL_ARRAY_BUFFER - glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x)); - glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r)); - glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u)); -+ - // Do the actual drawing operation, using the full set of vertices in the buffer -- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); -- // Release the buffer name for reuse -- glDeleteBuffers(1, &vertexBuffer); -+ glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size); - - g_matrices.PopMatrix(); - } -@@ -266,6 +250,48 @@ void CGUIFontTTFGL::LastEnd() - #endif - } - -+#if HAS_GLES -+CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector &vertices) const -+{ -+ // Rearrange the vertices to describe triangles -+ std::vector triangleVertices; -+ triangleVertices.reserve(vertices.size() * 6 / 4); -+ for (size_t i = 0; i < vertices.size(); i += 4) -+ { -+ triangleVertices.push_back(vertices[i]); -+ triangleVertices.push_back(vertices[i+1]); -+ triangleVertices.push_back(vertices[i+2]); -+ triangleVertices.push_back(vertices[i+1]); -+ triangleVertices.push_back(vertices[i+3]); -+ triangleVertices.push_back(vertices[i+2]); -+ } -+ -+ // Generate a unique buffer object name and put it in bufferHandle -+ GLuint bufferHandle; -+ glGenBuffers(1, &bufferHandle); -+ // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point -+ glBindBuffer(GL_ARRAY_BUFFER, bufferHandle); -+ // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER -+ // binding point (i.e. our buffer object) and initialise it from the -+ // specified client-side pointer -+ glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW); -+ // Unbind GL_ARRAY_BUFFER -+ glBindBuffer(GL_ARRAY_BUFFER, 0); -+ -+ return CVertexBuffer((void *) bufferHandle, vertices.size() / 4, this); -+} -+ -+void CGUIFontTTFGL::DestroyVertexBuffer(CVertexBuffer &buffer) const -+{ -+ if (buffer.bufferHandle != 0) -+ { -+ // Release the buffer name for reuse -+ glDeleteBuffers(1, (GLuint *) &buffer.bufferHandle); -+ buffer.bufferHandle = 0; -+ } -+} -+#endif -+ - CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) - { - newHeight = CBaseTexture::PadPow2(newHeight); -diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h -index 735fb3a..6102c90 100644 ---- a/xbmc/guilib/GUIFontTTFGL.h -+++ b/xbmc/guilib/GUIFontTTFGL.h -@@ -29,6 +29,7 @@ - - - #include "GUIFontTTF.h" +#include "system.h" - - - /*! -@@ -43,6 +44,10 @@ class CGUIFontTTFGL : public CGUIFontTTFBase - - virtual bool FirstBegin(); - virtual void LastEnd(); -+#if HAS_GLES -+ virtual CVertexBuffer CreateVertexBuffer(const std::vector &vertices) const; -+ virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const; -+#endif - - protected: - virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); --- -2.0.4 - - -From 9b56dce00a1e508113c836461eb45e51f632d469 Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Thu, 16 Jan 2014 16:29:42 +0000 -Subject: [PATCH 13/98] Switch from glDrawArrays() to glDrawElements(). - -This involves setting up a static VBO containing the indexes necessary to -convert from quads to triangles on the fly in the GPU. ---- - xbmc/guilib/GUIFontTTFGL.cpp | 72 +++++++++++++++++++++++++------------ - xbmc/guilib/GUIFontTTFGL.h | 11 +++++- - xbmc/windowing/egl/WinSystemEGL.cpp | 17 +++++++++ - 3 files changed, 77 insertions(+), 23 deletions(-) - -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp -index aabb9a6..812662c 100644 ---- a/xbmc/guilib/GUIFontTTFGL.cpp -+++ b/xbmc/guilib/GUIFontTTFGL.cpp -@@ -207,6 +207,10 @@ void CGUIFontTTFGL::LastEnd() - if (m_vertexTrans.size() > 0) - { - // Deal with the vertices that can be hardware clipped and therefore translated + -+ // Bind our pre-calculated array to GL_ELEMENT_ARRAY_BUFFER -+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle); ++#if !defined(TARGET_RASPBERRY_PI) + - for (size_t i = 0; i < m_vertexTrans.size(); i++) - { - // Apply the clip rectangle -@@ -222,14 +226,21 @@ void CGUIFontTTFGL::LastEnd() - // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point - glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle); + #include "ActiveAEResample.h" + #include "utils/log.h" -- // Set up the offsets of the various vertex attributes within the buffer -- // object bound to GL_ARRAY_BUFFER -- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x)); -- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r)); -- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u)); -+ // Do the actual drawing operation, split into groups of characters no -+ // larger than the pre-determined size of the element array -+ for (size_t character = 0; m_vertexTrans[i].vertexBuffer->size > character; character += ELEMENT_ARRAY_MAX_CHAR_INDEX) -+ { -+ size_t count = m_vertexTrans[i].vertexBuffer->size - character; -+ count = std::min(count, ELEMENT_ARRAY_MAX_CHAR_INDEX); -+ -+ // Set up the offsets of the various vertex attributes within the buffer -+ // object bound to GL_ARRAY_BUFFER -+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, x))); -+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, r))); -+ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, u))); - -- // Do the actual drawing operation, using the full set of vertices in the buffer -- glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size); -+ glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0); -+ } - - g_matrices.PopMatrix(); - } -@@ -237,8 +248,9 @@ void CGUIFontTTFGL::LastEnd() - g_Windowing.ResetScissors(); - // Restore the original model view matrix - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); -- // Unbind GL_ARRAY_BUFFER -+ // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER - glBindBuffer(GL_ARRAY_BUFFER, 0); -+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - // Disable the attributes used by this shader -@@ -253,19 +265,6 @@ void CGUIFontTTFGL::LastEnd() - #if HAS_GLES - CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector &vertices) const +@@ -386,3 +390,4 @@ int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layo { -- // Rearrange the vertices to describe triangles -- std::vector triangleVertices; -- triangleVertices.reserve(vertices.size() * 6 / 4); -- for (size_t i = 0; i < vertices.size(); i += 4) -- { -- triangleVertices.push_back(vertices[i]); -- triangleVertices.push_back(vertices[i+1]); -- triangleVertices.push_back(vertices[i+2]); -- triangleVertices.push_back(vertices[i+1]); -- triangleVertices.push_back(vertices[i+3]); -- triangleVertices.push_back(vertices[i+2]); -- } -- - // Generate a unique buffer object name and put it in bufferHandle - GLuint bufferHandle; - glGenBuffers(1, &bufferHandle); -@@ -274,7 +273,7 @@ CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector &vert - // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER - // binding point (i.e. our buffer object) and initialise it from the - // specified client-side pointer -- glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW); -+ glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), &vertices[0], GL_STATIC_DRAW); - // Unbind GL_ARRAY_BUFFER - glBindBuffer(GL_ARRAY_BUFFER, 0); + return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); + } ++#endif +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h +index a471e02..5d37cc7 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h +@@ -19,6 +19,8 @@ + * + */ -@@ -393,4 +392,33 @@ void CGUIFontTTFGL::DeleteHardwareTexture() - } ++#include "system.h" ++ + #include "cores/AudioEngine/Utils/AEChannelInfo.h" + #include "cores/AudioEngine/Utils/AEAudioFormat.h" + #include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h" +@@ -29,6 +31,10 @@ extern "C" { + #include "libswresample/swresample.h" } -+#if HAS_GLES -+void CGUIFontTTFGL::CreateStaticVertexBuffers(void) -+{ -+ // Bind a new buffer to the OpenGL context's GL_ELEMENT_ARRAY_BUFFER binding point -+ glGenBuffers(1, &m_elementArrayHandle); -+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle); -+ // Create an array holding the mesh indices to convert quads to triangles -+ GLushort index[ELEMENT_ARRAY_MAX_CHAR_INDEX][6]; -+ for (size_t i = 0; i < ELEMENT_ARRAY_MAX_CHAR_INDEX; i++) -+ { -+ index[i][0] = 4*i; -+ index[i][1] = 4*i+1; -+ index[i][2] = 4*i+2; -+ index[i][3] = 4*i+1; -+ index[i][4] = 4*i+3; -+ index[i][5] = 4*i+2; -+ } -+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof index, index, GL_STATIC_DRAW); -+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -+} -+ -+void CGUIFontTTFGL::DestroyStaticVertexBuffers(void) -+{ -+ glDeleteBuffers(1, &m_elementArrayHandle); -+} -+ -+GLuint CGUIFontTTFGL::m_elementArrayHandle; -+#endif -+ - #endif -diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h -index 6102c90..dcf9ca1 100644 ---- a/xbmc/guilib/GUIFontTTFGL.h -+++ b/xbmc/guilib/GUIFontTTFGL.h -@@ -30,6 +30,7 @@ - - #include "GUIFontTTF.h" - #include "system.h" -+#include "system_gl.h" - - - /*! -@@ -47,13 +48,21 @@ class CGUIFontTTFGL : public CGUIFontTTFBase - #if HAS_GLES - virtual CVertexBuffer CreateVertexBuffer(const std::vector &vertices) const; - virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const; -+ static void CreateStaticVertexBuffers(void); -+ static void DestroyStaticVertexBuffers(void); - #endif - - protected: - virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); - virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2); - virtual void DeleteHardwareTexture(); -- -+ -+#if HAS_GLES -+#define ELEMENT_ARRAY_MAX_CHAR_INDEX (1000) -+ -+ static GLuint m_elementArrayHandle; -+#endif -+ - private: - unsigned int m_updateY1; - unsigned int m_updateY2; -diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp -index 6de3532..258a293 100644 ---- a/xbmc/windowing/egl/WinSystemEGL.cpp -+++ b/xbmc/windowing/egl/WinSystemEGL.cpp -@@ -29,6 +29,7 @@ - #include "settings/AdvancedSettings.h" - #include "settings/Settings.h" - #include "settings/DisplaySettings.h" -+#include "guilib/GUIFontTTFGL.h" - #include "utils/log.h" - #include "EGLWrapper.h" - #include "EGLQuirks.h" -@@ -193,6 +194,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res) - return false; - } - -+#if HAS_GLES -+ bool newContext = false; -+#endif - if (m_context == EGL_NO_CONTEXT) - { - if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context)) -@@ -200,6 +204,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res) - CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__); - return false; - } -+#if HAS_GLES -+ newContext = true; -+#endif - } - - if (!m_egl->BindContext(m_display, m_surface, m_context)) -@@ -208,6 +215,11 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res) - return false; - } - -+#if HAS_GLES -+ if (newContext) -+ CGUIFontTTFGL::CreateStaticVertexBuffers(); -+#endif -+ - // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates - if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION || - g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION) -@@ -229,7 +241,12 @@ bool CWinSystemEGL::DestroyWindowSystem() - DestroyWindow(); - - if (m_context != EGL_NO_CONTEXT) -+ { -+#if HAS_GLES -+ CGUIFontTTFGL::DestroyStaticVertexBuffers(); -+#endif - m_egl->DestroyContext(m_display, m_context); -+ } - m_context = EGL_NO_CONTEXT; - - if (m_display != EGL_NO_DISPLAY) --- -2.0.4 - - -From 2759a8cc4b06119f569a4b6803980e6623b3e1a8 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 10 Jan 2014 12:10:43 +0000 -Subject: [PATCH 14/98] [rbp] Don't override dvdplayer with omxplayer. - -Using dvdplayer can be useful on the Pi. We can actually play sd (up to 640x480 MPEG-4 video) video in real time. -This is useful for codec variants like DivX3 which we don't currently play. - -This may expose bugs where dvdplayer is incorrectly used as the default player which will need to be fixed ---- - xbmc/cores/playercorefactory/PlayerCoreConfig.h | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h -index c590cca..57b524f 100644 ---- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h -+++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h -@@ -98,14 +98,7 @@ friend class CPlayerCoreFactory; - { - case EPC_MPLAYER: - // TODO: this hack needs removal until we have a better player selection --#if defined(HAS_OMXPLAYER) -- case EPC_DVDPLAYER: -- pPlayer = new COMXPlayer(callback); -- CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as DVDPlayer", "OMXPlayer", m_eCore); -- break; --#else - case EPC_DVDPLAYER: pPlayer = new CDVDPlayer(callback); break; --#endif - case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break; - case EPC_EXTPLAYER: pPlayer = new CExternalPlayer(callback); break; - #if defined(HAS_OMXPLAYER) --- -2.0.4 - - -From ec9813a9b29125eb1fba01d29809a842c0d68d20 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 10 Jan 2014 15:37:41 +0000 -Subject: [PATCH 15/98] [players] Use default players rather than hard coded - DVDPlayer/PAPlayer - ---- - system/playercorefactory.xml | 23 ++++++++++++----------- - 1 file changed, 12 insertions(+), 11 deletions(-) - -diff --git a/system/playercorefactory.xml b/system/playercorefactory.xml -index 57dfcdd..7be9799 100644 ---- a/system/playercorefactory.xml -+++ b/system/playercorefactory.xml -@@ -11,31 +11,32 @@ - - - -- -- -- -+ -+ -+ - - - -- -+ - - - -- -- -+ -+ - - - -- -- -+ -+ -+ - - -- -+ - - -- -+ - - -- -+ - - --- -2.0.4 - - -From 7250a8b81f2fb50019aa1ac1e0e997099f2759c4 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sat, 11 Jan 2014 18:23:42 +0000 -Subject: [PATCH 16/98] [rbp] Don't force dvdplayer for airplay - ---- - xbmc/network/AirPlayServer.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp -index 5900efd..3e16250 100644 ---- a/xbmc/network/AirPlayServer.cpp -+++ b/xbmc/network/AirPlayServer.cpp -@@ -903,9 +903,11 @@ int CAirPlayServer::CTCPClient::ProcessRequest( std::string& responseHeader, - CFileItem fileToPlay(location, false); - fileToPlay.SetProperty("StartPercent", position*100.0f); - ServerInstance->AnnounceToClients(EVENT_LOADING); -+#ifndef TARGET_RASPBERRY_PI - // froce to internal dvdplayer cause it is the only - // one who will work well with airplay - g_application.m_eForcedNextPlayer = EPC_DVDPLAYER; -+#endif - CApplicationMessenger::Get().MediaPlay(fileToPlay); - } - } --- -2.0.4 - - -From 6fe4ca96daca4cbe8313ea5a23b9c7a63a87e2dd Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 13 Jan 2014 13:11:06 +0000 -Subject: [PATCH 17/98] [rbp] Give plugins omxplayer when they request - dvdplayer on pi - ---- - xbmc/interfaces/legacy/ModuleXbmc.cpp | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp -index dfdca99..2a819ef 100644 ---- a/xbmc/interfaces/legacy/ModuleXbmc.cpp -+++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp -@@ -527,7 +527,11 @@ namespace XBMCAddon - int getPLAYLIST_MUSIC() { return PLAYLIST_MUSIC; } - int getPLAYLIST_VIDEO() { return PLAYLIST_VIDEO; } - int getPLAYER_CORE_AUTO() { return EPC_NONE; } -+#ifdef TARGET_RASPBERRY_PI -+ int getPLAYER_CORE_DVDPLAYER() { return EPC_OMXPLAYER; } ++#if defined(TARGET_RASPBERRY_PI) ++#include "ActiveAEResamplePi.h" +#else - int getPLAYER_CORE_DVDPLAYER() { return EPC_DVDPLAYER; } -+#endif - int getPLAYER_CORE_MPLAYER() { return EPC_MPLAYER; } - int getPLAYER_CORE_PAPLAYER() { return EPC_PAPLAYER; } - int getTRAY_OPEN() { return TRAY_OPEN; } --- -2.0.4 - - -From 27ab25cbc2859cf42613a557f89833920ffa40e0 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 14 Jan 2014 18:04:07 +0000 -Subject: [PATCH 18/98] [rbp] Allow ALSA to be chosen in addition to Pi sink - -Needs --enable-alsa in ./configure step and alsa support on platform ---- - configure.in | 1 - - tools/depends/target/Makefile | 5 +++-- - xbmc/cores/AudioEngine/AESinkFactory.cpp | 15 ++++++++++++++- - 3 files changed, 17 insertions(+), 4 deletions(-) - -diff --git a/configure.in b/configure.in -index 725a271..214c08d 100644 ---- a/configure.in -+++ b/configure.in -@@ -711,7 +711,6 @@ case $use_platform in - use_arch="arm" - use_cpu=arm1176jzf-s - use_hardcoded_tables="yes" -- use_alsa="no" - ARCH="arm" - AC_DEFINE(HAS_EGLGLES, [1], [Define if supporting EGL based GLES Framebuffer]) - USE_OMXLIB=1; AC_DEFINE([HAVE_OMXLIB],[1],["Define to 1 if OMX libs is enabled"]) -diff --git a/tools/depends/target/Makefile b/tools/depends/target/Makefile -index f5374b2..73a939c 100644 ---- a/tools/depends/target/Makefile -+++ b/tools/depends/target/Makefile -@@ -58,10 +58,11 @@ LINUX_SYSTEM_LIBS= - ifeq ($(OS),linux) - #not for raspberry pi - ifneq ($(TARGET_PLATFORM),raspberry-pi) -- DEPENDS += alsa-lib libsdl linux-system-libs -- ALSA_LIB = alsa-lib -+ DEPENDS += libsdl linux-system-libs - LINUX_SYSTEM_LIBS = linux-system-libs - endif -+ DEPENDS += alsa-lib -+ ALSA_LIB = alsa-lib - FFMPEG_DEPENDS = gnutls - endif - -diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp -index e42d973..715b4f1 100644 ---- a/xbmc/cores/AudioEngine/AESinkFactory.cpp -+++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp -@@ -27,6 +27,7 @@ - #include "Sinks/AESinkAUDIOTRACK.h" - #elif defined(TARGET_RASPBERRY_PI) - #include "Sinks/AESinkPi.h" -+ #include "Sinks/AESinkALSA.h" - #elif defined(TARGET_DARWIN_IOS) - #include "Sinks/AESinkDARWINIOS.h" - #elif defined(TARGET_DARWIN_OSX) -@@ -66,6 +67,7 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver) - driver == "AUDIOTRACK" || - #elif defined(TARGET_RASPBERRY_PI) - driver == "PI" || -+ driver == "ALSA" || - #elif defined(TARGET_DARWIN_IOS) - driver == "DARWINIOS" || - #elif defined(TARGET_DARWIN_OSX) -@@ -105,7 +107,12 @@ IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAud - #elif defined(TARGET_ANDROID) - sink = new CAESinkAUDIOTRACK(); - #elif defined(TARGET_RASPBERRY_PI) -+ if (driver == "PI") - sink = new CAESinkPi(); -+ #if defined(HAS_ALSA) -+ if (driver == "ALSA") -+ sink = new CAESinkALSA(); -+ #endif - #elif defined(TARGET_DARWIN_IOS) - sink = new CAESinkDARWINIOS(); - #elif defined(TARGET_DARWIN_OSX) -@@ -196,7 +203,13 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force) - CAESinkPi::EnumerateDevicesEx(info.m_deviceInfoList, force); - if(!info.m_deviceInfoList.empty()) - list.push_back(info); -- -+ #if defined(HAS_ALSA) -+ info.m_deviceInfoList.clear(); -+ info.m_sinkName = "ALSA"; -+ CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force); -+ if(!info.m_deviceInfoList.empty()) -+ list.push_back(info); -+ #endif - #elif defined(TARGET_DARWIN_IOS) - - info.m_deviceInfoList.clear(); --- -2.0.4 - - -From e7a4920bdd2b5c66886c61606da3b2b54c5967e8 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 16 Jan 2014 01:39:29 +0000 -Subject: [PATCH 19/98] [omxcodec] Add hardware decode to dvdplayer for Pi - -Hijack the abandoned OpenMaxVideo codec ---- - configure.in | 21 +- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 12 +- - xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 6 +- - xbmc/cores/VideoRenderers/RenderManager.cpp | 2 +- - xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 7 +- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 7 +- - .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 295 +--- - .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 34 +- - xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 1 - - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 1418 ++++++++++---------- - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 120 +- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 2 + - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 21 +- - xbmc/linux/OMXCore.cpp | 45 +- - xbmc/linux/OMXCore.h | 2 +- - 15 files changed, 894 insertions(+), 1099 deletions(-) - -diff --git a/configure.in b/configure.in -index 214c08d..d2b8322 100644 ---- a/configure.in -+++ b/configure.in -@@ -1858,9 +1858,24 @@ if test "$host_vendor" = "apple" ; then - USE_OPENMAX=0 - AC_MSG_NOTICE($openmax_disabled) - elif test "$target_platform" = "target_raspberry_pi"; then -- use_openmax="no" -- USE_OPENMAX=0 -- AC_MSG_NOTICE($openmax_disabled) -+ if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then -+ use_openmax="yes" -+ USE_OPENMAX=1 -+ HAVE_LIBOPENMAX=1 -+ AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.]) -+ AC_DEFINE([OMX_SKIP64BIT], [1], [Define to 1 if you have the 'LIBOPENMAX' library.]) -+ AC_MSG_NOTICE($openmax_enabled) -+ elif test "$use_gles" = "yes" && test "$use_openmax" = "yes"; then -+ use_openmax="yes" -+ USE_OPENMAX=1 -+ HAVE_LIBOPENMAX=1 -+ AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.]) -+ AC_MSG_NOTICE($openmax_enabled) -+ else -+ AC_MSG_NOTICE($openmax_disabled) -+ use_openmax=no -+ USE_OPENMAX=0 -+ fi - else - if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then - PKG_CHECK_MODULES([OPENMAX], [libomxil-bellagio], -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 72eb725..2e0d0ca 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -44,7 +44,7 @@ - #include "VideoShaders/VideoFilterShader.h" - #include "windowing/WindowingFactory.h" - #include "guilib/Texture.h" --#include "../dvdplayer/DVDCodecs/Video/OpenMaxVideo.h" -+#include "DVDCodecs/Video/OpenMaxVideo.h" - #include "threads/SingleLock.h" - #include "RenderCapture.h" - #include "RenderFormats.h" -@@ -1328,6 +1328,10 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field) - glActiveTexture(GL_TEXTURE0); - glBindTexture(m_textureTarget, textureId); - -+ GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); + - g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA); - - GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip -@@ -2674,10 +2678,12 @@ unsigned int CLinuxRendererGLES::GetProcessorSize() - } - - #ifdef HAVE_LIBOPENMAX --void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index) -+void CLinuxRendererGLES::AddProcessor(COpenMaxVideoBuffer *openMaxBuffer, int index) + namespace ActiveAE { - YUVBUFFER &buf = m_buffers[index]; -- buf.openMaxBuffer = picture->openMaxBuffer; -+ COpenMaxVideoBuffer *pic = openMaxBuffer->Acquire(); -+ SAFE_RELEASE(buf.openMaxBuffer); -+ buf.openMaxBuffer = pic; - } - #endif - #ifdef HAVE_VIDEOTOOLBOXDECODER -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -index 642cded..5a6a2be 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -@@ -39,7 +39,7 @@ class CRenderCapture; - class CBaseTexture; - namespace Shaders { class BaseYUV2RGBShader; } - namespace Shaders { class BaseVideoFilterShader; } --class COpenMaxVideo; -+class COpenMaxVideoBuffer; - class CDVDVideoCodecStageFright; - class CDVDMediaCodecInfo; - typedef std::vector Features; -@@ -158,7 +158,7 @@ class CLinuxRendererGLES : public CBaseRenderer - virtual std::vector SupportedFormats() { return m_formats; } - #ifdef HAVE_LIBOPENMAX -- virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index); -+ virtual void AddProcessor(COpenMaxVideoBuffer *openMaxVideoBuffer, int index); - #endif - #ifdef HAVE_VIDEOTOOLBOXDECODER - virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); -@@ -272,7 +272,7 @@ class CLinuxRendererGLES : public CBaseRenderer - unsigned flipindex; /* used to decide if this has been uploaded */ - - #ifdef HAVE_LIBOPENMAX -- OpenMaxVideoBuffer *openMaxBuffer; -+ COpenMaxVideoBuffer *openMaxBuffer; - #endif - #ifdef HAVE_VIDEOTOOLBOXDECODER - struct __CVBuffer *cvBufferRef; -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp -index b6fb1a3..be3ce46 100644 ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp -@@ -914,7 +914,7 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) - #endif - #ifdef HAVE_LIBOPENMAX - else if(pic.format == RENDER_FMT_OMXEGL) -- m_pRenderer->AddProcessor(pic.openMax, &pic, index); -+ m_pRenderer->AddProcessor(pic.openMaxBuffer, index); - #endif - #ifdef TARGET_DARWIN - else if(pic.format == RENDER_FMT_CVBREF) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -index 181d755..34cc95d 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -@@ -236,9 +236,12 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne - #endif - - #if defined(HAVE_LIBOPENMAX) -- if (CSettings::Get().GetBool("videoplayer.useomx") && !hint.software ) -+ if (!hint.software && CSettings::Get().GetBool("videoplayer.useomx")) - { -- if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_VC1) -+ if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_H263 || hint.codec == AV_CODEC_ID_MPEG4 || -+ hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO || -+ hint.codec == AV_CODEC_ID_VP6 || hint.codec == AV_CODEC_ID_VP6F || hint.codec == AV_CODEC_ID_VP6A || hint.codec == AV_CODEC_ID_VP8 || -+ hint.codec == AV_CODEC_ID_THEORA || hint.codec == AV_CODEC_ID_MJPEG || hint.codec == AV_CODEC_ID_MJPEGB || hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) - { - if ( (pCodec = OpenCodec(new CDVDVideoCodecOpenMax(), hint, options)) ) return pCodec; - } -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -index 741017d..7daed00 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h -@@ -48,9 +48,7 @@ struct DVDCodecAvailableType - namespace DXVA { class CSurfaceContext; } - namespace VAAPI { struct CHolder; } - namespace VDPAU { class CVdpauRenderPicture; } --class COpenMax; --class COpenMaxVideo; --struct OpenMaxVideoBuffer; -+class COpenMaxVideoBuffer; - class CDVDVideoCodecStageFright; - class CDVDMediaCodecInfo; - typedef void* EGLImageKHR; -@@ -79,8 +77,7 @@ struct DVDVideoPicture - }; - - struct { -- COpenMax *openMax; -- OpenMaxVideoBuffer *openMaxBuffer; -+ COpenMaxVideoBuffer *openMaxBuffer; - }; - - struct { -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -index b2e7816..7d33192 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -@@ -29,113 +29,43 @@ - #include "DVDStreamInfo.h" - #include "DVDVideoCodecOpenMax.h" - #include "OpenMaxVideo.h" -+#include "settings/Settings.h" - #include "utils/log.h" - --#define CLASSNAME "COpenMax" -+#define CLASSNAME "CDVDVideoCodecOpenMax" - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// --CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() : CDVDVideoCodec() -+CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() - { - m_omx_decoder = NULL; -- m_pFormatName = "omx-xxxx"; -- -- m_convert_bitstream = false; -- memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); -+ CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this); - } - - CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax() - { -+ CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this); - Dispose(); - } - - bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - { -- // we always qualify even if DVDFactoryCodec does this too. -- if (CSettings::Get().GetBool("videoplayer.useomx") && !hints.software) -- { -- m_convert_bitstream = false; -- -- switch (hints.codec) -- { -- case AV_CODEC_ID_H264: -- { -- m_pFormatName = "omx-h264"; -- if (hints.extrasize < 7 || hints.extradata == NULL) -- { -- CLog::Log(LOGNOTICE, -- "%s::%s - avcC data too small or missing", CLASSNAME, __func__); -- return false; -- } -- // valid avcC data (bitstream) always starts with the value 1 (version) -- if ( *(char*)hints.extradata == 1 ) -- m_convert_bitstream = bitstream_convert_init(hints.extradata, hints.extrasize); -- } -- break; -- case AV_CODEC_ID_MPEG4: -- m_pFormatName = "omx-mpeg4"; -- break; -- case AV_CODEC_ID_MPEG2VIDEO: -- m_pFormatName = "omx-mpeg2"; -- break; -- case AV_CODEC_ID_VC1: -- m_pFormatName = "omx-vc1"; -- break; -- default: -- return false; -- break; -- } -- -- m_omx_decoder = new COpenMaxVideo; -- if (!m_omx_decoder->Open(hints)) -- { -- CLog::Log(LOGERROR, -- "%s::%s - failed to open, codec(%d), profile(%d), level(%d)", -- CLASSNAME, __func__, hints.codec, hints.profile, hints.level); -- return false; -- } -- -- // allocate a YV12 DVDVideoPicture buffer. -- // first make sure all properties are reset. -- memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); -- -- m_videobuffer.dts = DVD_NOPTS_VALUE; -- m_videobuffer.pts = DVD_NOPTS_VALUE; -- //m_videobuffer.format = RENDER_FMT_YUV420P; -- m_videobuffer.format = RENDER_FMT_OMXEGL; -- m_videobuffer.color_range = 0; -- m_videobuffer.color_matrix = 4; -- m_videobuffer.iFlags = DVP_FLAG_ALLOCATED; -- m_videobuffer.iWidth = hints.width; -- m_videobuffer.iHeight = hints.height; -- m_videobuffer.iDisplayWidth = hints.width; -- m_videobuffer.iDisplayHeight = hints.height; -- -- return true; -- } -+ m_omx_decoder = new COpenMaxVideo; -+ return m_omx_decoder->Open(hints, options); -+} - -- return false; -+const char* CDVDVideoCodecOpenMax::GetName(void) -+{ -+ return m_omx_decoder ? m_omx_decoder->GetName() : "omx-xxx"; - } - - void CDVDVideoCodecOpenMax::Dispose() - { - if (m_omx_decoder) - { -- m_omx_decoder->Close(); -+ m_omx_decoder->Dispose(); - delete m_omx_decoder; - m_omx_decoder = NULL; - } -- if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED) -- { -- m_videobuffer.iFlags = 0; -- } -- if (m_convert_bitstream) -- { -- if (m_sps_pps_context.sps_pps_data) -- { -- free(m_sps_pps_context.sps_pps_data); -- m_sps_pps_context.sps_pps_data = NULL; -- } -- } - } - - void CDVDVideoCodecOpenMax::SetDropState(bool bDrop) -@@ -145,37 +75,12 @@ void CDVDVideoCodecOpenMax::SetDropState(bool bDrop) - - int CDVDVideoCodecOpenMax::Decode(uint8_t* pData, int iSize, double dts, double pts) - { -- if (pData) -- { -- int rtn; -- int demuxer_bytes = iSize; -- uint8_t *demuxer_content = pData; -- bool bitstream_convered = false; -- -- if (m_convert_bitstream) -- { -- // convert demuxer packet from bitstream to bytestream (AnnexB) -- int bytestream_size = 0; -- uint8_t *bytestream_buff = NULL; -- -- bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size); -- if (bytestream_buff && (bytestream_size > 0)) -- { -- bitstream_convered = true; -- demuxer_bytes = bytestream_size; -- demuxer_content = bytestream_buff; -- } -- } -- -- rtn = m_omx_decoder->Decode(demuxer_content, demuxer_bytes, dts, pts); -- -- if (bitstream_convered) -- free(demuxer_content); -+ return m_omx_decoder->Decode(pData, iSize, dts, pts); -+} - -- return rtn; -- } -- -- return VC_BUFFER; -+unsigned CDVDVideoCodecOpenMax::GetAllowedReferences() -+{ -+ return m_omx_decoder->GetAllowedReferences(); - } - - void CDVDVideoCodecOpenMax::Reset(void) -@@ -185,172 +90,12 @@ void CDVDVideoCodecOpenMax::Reset(void) - - bool CDVDVideoCodecOpenMax::GetPicture(DVDVideoPicture* pDvdVideoPicture) - { -- m_omx_decoder->GetPicture(&m_videobuffer); -- *pDvdVideoPicture = m_videobuffer; -- -- return VC_PICTURE | VC_BUFFER; --} -- --//////////////////////////////////////////////////////////////////////////////////////////// --bool CDVDVideoCodecOpenMax::bitstream_convert_init(void *in_extradata, int in_extrasize) --{ -- // based on h264_mp4toannexb_bsf.c (ffmpeg) -- // which is Copyright (c) 2007 Benoit Fouet -- // and Licensed GPL 2.1 or greater -- -- m_sps_pps_size = 0; -- m_sps_pps_context.sps_pps_data = NULL; -- -- // nothing to filter -- if (!in_extradata || in_extrasize < 6) -- return false; -- -- uint16_t unit_size; -- uint32_t total_size = 0; -- uint8_t *out = NULL, unit_nb, sps_done = 0; -- const uint8_t *extradata = (uint8_t*)in_extradata + 4; -- static const uint8_t nalu_header[4] = {0, 0, 0, 1}; -- -- // retrieve length coded size -- m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1; -- if (m_sps_pps_context.length_size == 3) -- return false; -- -- // retrieve sps and pps unit(s) -- unit_nb = *extradata++ & 0x1f; // number of sps unit(s) -- if (!unit_nb) -- { -- unit_nb = *extradata++; // number of pps unit(s) -- sps_done++; -- } -- while (unit_nb--) -- { -- unit_size = extradata[0] << 8 | extradata[1]; -- total_size += unit_size + 4; -- if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) ) -- { -- free(out); -- return false; -- } -- uint8_t* new_out = (uint8_t*)realloc(out, total_size); -- if (new_out) -- { -- out = new_out; -- } -- else -- { -- CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out", __FUNCTION__); -- free(out); -- return false; -- } -- -- memcpy(out + total_size - unit_size - 4, nalu_header, 4); -- memcpy(out + total_size - unit_size, extradata + 2, unit_size); -- extradata += 2 + unit_size; -- -- if (!unit_nb && !sps_done++) -- unit_nb = *extradata++; // number of pps unit(s) -- } -- -- m_sps_pps_context.sps_pps_data = out; -- m_sps_pps_context.size = total_size; -- m_sps_pps_context.first_idr = 1; -- -- return true; --} -- --bool CDVDVideoCodecOpenMax::bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size) --{ -- // based on h264_mp4toannexb_bsf.c (ffmpeg) -- // which is Copyright (c) 2007 Benoit Fouet -- // and Licensed GPL 2.1 or greater -- -- uint8_t *buf = pData; -- uint32_t buf_size = iSize; -- uint8_t unit_type; -- int32_t nal_size; -- uint32_t cumul_size = 0; -- const uint8_t *buf_end = buf + buf_size; -- -- do -- { -- if (buf + m_sps_pps_context.length_size > buf_end) -- goto fail; -- -- if (m_sps_pps_context.length_size == 1) -- nal_size = buf[0]; -- else if (m_sps_pps_context.length_size == 2) -- nal_size = buf[0] << 8 | buf[1]; -- else -- nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; -- -- buf += m_sps_pps_context.length_size; -- unit_type = *buf & 0x1f; -- -- if (buf + nal_size > buf_end || nal_size < 0) -- goto fail; -- -- // prepend only to the first type 5 NAL unit of an IDR picture -- if (m_sps_pps_context.first_idr && unit_type == 5) -- { -- bitstream_alloc_and_copy(poutbuf, poutbuf_size, -- m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size); -- m_sps_pps_context.first_idr = 0; -- } -- else -- { -- bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size); -- if (!m_sps_pps_context.first_idr && unit_type == 1) -- m_sps_pps_context.first_idr = 1; -- } -- -- buf += nal_size; -- cumul_size += nal_size + m_sps_pps_context.length_size; -- } while (cumul_size < buf_size); -- -- return true; -- --fail: -- free(*poutbuf); -- *poutbuf = NULL; -- *poutbuf_size = 0; -- return false; -+ return m_omx_decoder->GetPicture(pDvdVideoPicture); - } - --void CDVDVideoCodecOpenMax::bitstream_alloc_and_copy( -- uint8_t **poutbuf, int *poutbuf_size, -- const uint8_t *sps_pps, uint32_t sps_pps_size, -- const uint8_t *in, uint32_t in_size) -+bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture) - { -- // based on h264_mp4toannexb_bsf.c (ffmpeg) -- // which is Copyright (c) 2007 Benoit Fouet -- // and Licensed GPL 2.1 or greater -- -- #define CHD_WB32(p, d) { \ -- ((uint8_t*)(p))[3] = (d); \ -- ((uint8_t*)(p))[2] = (d) >> 8; \ -- ((uint8_t*)(p))[1] = (d) >> 16; \ -- ((uint8_t*)(p))[0] = (d) >> 24; } -- -- uint32_t offset = *poutbuf_size; -- uint8_t nal_header_size = offset ? 3 : 4; -- -- *poutbuf_size += sps_pps_size + in_size + nal_header_size; -- *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size); -- if (sps_pps) -- memcpy(*poutbuf + offset, sps_pps, sps_pps_size); -- -- memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); -- if (!offset) -- { -- CHD_WB32(*poutbuf + sps_pps_size, 1); -- } -- else -- { -- (*poutbuf + offset + sps_pps_size)[0] = 0; -- (*poutbuf + offset + sps_pps_size)[1] = 0; -- (*poutbuf + offset + sps_pps_size)[2] = 1; -- } -+ return m_omx_decoder->ClearPicture(pDvdVideoPicture); - } - - #endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -index fb80d02..67cc235 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -@@ -23,7 +23,7 @@ - - #include "DVDVideoCodec.h" - --class COpenVideoMax; -+class COpenMaxVideo; - class CDVDVideoCodecOpenMax : public CDVDVideoCodec - { - public: -@@ -36,39 +36,13 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec - virtual int Decode(uint8_t *pData, int iSize, double dts, double pts); - virtual void Reset(void); - virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture); -+ virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); -+ virtual unsigned GetAllowedReferences(); - virtual void SetDropState(bool bDrop); -- virtual const char* GetName(void) { return (const char*)m_pFormatName; } -+ virtual const char* GetName(void); - - protected: -- const char *m_pFormatName; - COpenMaxVideo *m_omx_decoder; -- DVDVideoPicture m_videobuffer; -- -- // bitstream to bytestream (Annex B) conversion support. -- bool bitstream_convert_init(void *in_extradata, int in_extrasize); -- bool bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size); -- static void bitstream_alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size, -- const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size); -- -- typedef struct omx_bitstream_ctx { -- uint8_t length_size; -- uint8_t first_idr; -- uint8_t *sps_pps_data; -- uint32_t size; -- -- omx_bitstream_ctx() -- { -- length_size = 0; -- first_idr = 0; -- sps_pps_data = NULL; -- size = 0; -- } -- -- } omx_bitstream_ctx; -- -- uint32_t m_sps_pps_size; -- omx_bitstream_ctx m_sps_pps_context; -- bool m_convert_bitstream; +@@ -63,3 +69,5 @@ class CActiveAEResample }; - #endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -index 9c13da8..390d940 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in -@@ -16,7 +16,6 @@ SRCS += DVDVideoCodecVDA.cpp - SRCS += VDA.cpp - endif - ifeq (@USE_OPENMAX@,1) --SRCS += OpenMax.cpp - SRCS += OpenMaxVideo.cpp - SRCS += DVDVideoCodecOpenMax.cpp - endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index dcbdb1e..aca2e0d 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -32,673 +32,891 @@ - #include "DVDVideoCodec.h" - #include "utils/log.h" - #include "utils/TimeUtils.h" + } ++ ++#endif +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp +new file mode 100644 +index 0000000..cc01738 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp +@@ -0,0 +1,656 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "system.h" ++ ++#if defined(TARGET_RASPBERRY_PI) ++ ++#include "ActiveAEResample.h" ++#include "linux/RBP.h" +#include "settings/Settings.h" - #include "ApplicationMessenger.h" - #include "Application.h" -+#include "threads/Atomics.h" - --#include --#include --#include --#include -+#include -+#include -+#include -+#include - -+#include "cores/omxplayer/OMXImage.h" ++#include "utils/log.h" + -+#define DTS_QUEUE ++extern "C" { ++#include "libavutil/channel_layout.h" ++#include "libavutil/opt.h" ++#include "libswresample/swresample.h" ++} + -+#define DEFAULT_TIMEOUT 1000 -+#ifdef _DEBUG -+#define OMX_DEBUG_VERBOSE ++//#define DEBUG_VERBOSE ++ ++#define CLASSNAME "CActiveAEResamplePi" ++ ++#define BUFFERSIZE (32*1024*2*8) ++ ++//#define BENCHMARKING ++#ifdef BENCHMARKING ++#define LOGTIMEINIT(f) \ ++ struct timespec now; \ ++ uint64_t Start, End; \ ++ clock_gettime(CLOCK_MONOTONIC, &now); \ ++ Start = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \ ++ const char *_filename = f; ++ ++#define LOGTIME(n) \ ++ clock_gettime(CLOCK_MONOTONIC, &now); \ ++ End = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \ ++ CLog::Log(LOGNOTICE, "ActiveAE::%s %d - resample %s took %.0fms", __FUNCTION__, n, _filename, (End-Start)*1e-6); \ ++ Start=End; ++#else ++#define LOGTIMEINIT(f) ++#define LOGTIME(n) +#endif - - #define CLASSNAME "COpenMaxVideo" - --// TODO: These are Nvidia Tegra2 dependent, need to dynamiclly find the --// right codec matched to video format. --#define OMX_H264BASE_DECODER "OMX.Nvidia.h264.decode" --// OMX.Nvidia.h264ext.decode segfaults, not sure why. --//#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264ext.decode" --#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264.decode" --#define OMX_H264HIGH_DECODER "OMX.Nvidia.h264ext.decode" --#define OMX_MPEG4_DECODER "OMX.Nvidia.mp4.decode" --#define OMX_MPEG4EXT_DECODER "OMX.Nvidia.mp4ext.decode" --#define OMX_MPEG2V_DECODER "OMX.Nvidia.mpeg2v.decode" --#define OMX_VC1_DECODER "OMX.Nvidia.vc1.decode" -- --// EGL extension functions --static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; --static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; --#define GETEXTENSION(type, ext) \ --do \ --{ \ -- ext = (type) eglGetProcAddress(#ext); \ -- if (!ext) \ -- { \ -- CLog::Log(LOGERROR, "%s::%s - ERROR getting proc addr of " #ext "\n", CLASSNAME, __func__); \ -- } \ --} while (0); -- --#define OMX_INIT_STRUCTURE(a) \ -- memset(&(a), 0, sizeof(a)); \ -- (a).nSize = sizeof(a); \ -- (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \ -- (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \ -- (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \ -- (a).nVersion.s.nStep = OMX_VERSION_STEP -+COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv) -+ : m_omv(omv), m_refs(0) ++ ++using namespace ActiveAE; ++ ++CActiveAEResample::CActiveAEResample() +{ -+ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); -+ omx_buffer = NULL; -+ width = 0; -+ height = 0; -+ index = 0; -+ egl_image = 0; -+ texture_id = 0; ++ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ ++ m_Initialized = false; ++ m_last_src_fmt = AV_SAMPLE_FMT_NONE; ++ m_last_dst_fmt = AV_SAMPLE_FMT_NONE; ++ m_last_src_channels = 0; ++ m_last_dst_channels = 0; ++ m_encoded_buffer = NULL; +} + -+COpenMaxVideoBuffer::~COpenMaxVideoBuffer() ++CActiveAEResample::~CActiveAEResample() +{ -+ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); -+} - - --COpenMaxVideo::COpenMaxVideo() -+// DecoderFillBufferDone -- OpenMax output buffer has been filled -+static OMX_ERRORTYPE DecoderFillBufferDoneCallback( -+ OMX_HANDLETYPE hComponent, -+ OMX_PTR pAppData, -+ OMX_BUFFERHEADERTYPE* pBuffer) -+{ -+ COpenMaxVideoBuffer *pic = static_cast(pBuffer->pAppPrivate); -+ COpenMaxVideo *ctx = pic->m_omv; -+ return ctx->DecoderFillBufferDone(hComponent, pBuffer); ++ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ DeInit(); +} + -+ -+COpenMaxVideoBuffer* COpenMaxVideoBuffer::Acquire() ++void CActiveAEResample::DeInit() +{ -+ long count = AtomicIncrement(&m_refs); -+ #if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, count); -+ #endif -+ (void)count; -+ return this; -+} -+ -+long COpenMaxVideoBuffer::Release() - { -- m_portChanging = false; -+ long count = AtomicDecrement(&m_refs); -+ if (count == 0) ++ CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__); ++ if (m_Initialized) + { -+ m_omv->ReleaseOpenMaxBuffer(this); ++ m_omx_mixer.FlushAll(); ++ m_omx_mixer.Deinitialize(); ++ m_Initialized = false; + } -+ -+ #if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, count); -+ #endif -+ return count; -+} - -- pthread_mutex_init(&m_omx_input_mutex, NULL); -+void COpenMaxVideoBuffer::Sync() -+{ -+ #if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, m_refs); -+ #endif -+ Release(); +} + -+COpenMaxVideo::COpenMaxVideo() ++static int format_to_bits(AVSampleFormat fmt) +{ -+ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); - pthread_mutex_init(&m_omx_output_mutex, NULL); - -- m_omx_decoder_state_change = (sem_t*)malloc(sizeof(sem_t)); -- sem_init(m_omx_decoder_state_change, 0, 0); -- memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); - m_drop_state = false; - m_decoded_width = 0; - m_decoded_height = 0; -- m_omx_input_eos = false; -- m_omx_input_port = 0; -- m_omx_output_eos = false; -- m_omx_output_port = 0; -- m_videoplayback_done = false; -+ m_egl_buffer_count = 0; -+ -+ m_port_settings_changed = false; -+ m_pFormatName = "omx-xxxx"; - } - - COpenMaxVideo::~COpenMaxVideo() - { - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); -+ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); - #endif -- if (m_is_open) -- Close(); -- pthread_mutex_destroy(&m_omx_input_mutex); -+ if (m_omx_decoder.IsInitialized()) ++ switch (fmt) + { -+ if (m_omx_tunnel.IsInitialized()) -+ m_omx_tunnel.Deestablish(); -+ -+ StopDecoder(); -+ -+ if (m_omx_egl_render.IsInitialized()) -+ m_omx_egl_render.Deinitialize(); -+ if (m_omx_decoder.IsInitialized()) -+ m_omx_decoder.Deinitialize(); ++ case AV_SAMPLE_FMT_U8: ++ case AV_SAMPLE_FMT_U8P: ++ return 8; ++ case AV_SAMPLE_FMT_S16: ++ case AV_SAMPLE_FMT_S16P: ++ return 16; ++ case AV_SAMPLE_FMT_S32: ++ case AV_SAMPLE_FMT_S32P: ++ case AV_SAMPLE_FMT_FLT: ++ case AV_SAMPLE_FMT_FLTP: ++ return 32; ++ default: ++ assert(0); + } - pthread_mutex_destroy(&m_omx_output_mutex); -- sem_destroy(m_omx_decoder_state_change); -- free(m_omx_decoder_state_change); - } - --bool COpenMaxVideo::Open(CDVDStreamInfo &hints) -+bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - { - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); -+ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - #endif - -+ // we always qualify even if DVDFactoryCodec does this too. -+ if (!CSettings::Get().GetBool("videoplayer.useomx") || hints.software) -+ return false; ++ return 0; ++} + - OMX_ERRORTYPE omx_err = OMX_ErrorNone; -- std::string decoder_name; - - m_decoded_width = hints.width; - m_decoded_height = hints.height; - -+ m_egl_display = g_Windowing.GetEGLDisplay(); -+ m_egl_context = g_Windowing.GetEGLContext(); -+ m_egl_buffer_count = 4; ++bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality) ++{ ++ LOGTIMEINIT("x"); + -+ m_codingType = OMX_VIDEO_CodingUnused; ++ CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d rate:%d->%d format:%d->%d bits:%d->%d norm:%d upmix:%d", CLASSNAME, __func__, remapLayout, src_channels, dst_channels, src_rate, dst_rate, src_fmt, dst_fmt, src_bits, dst_bits, normalize, upmix); + - switch (hints.codec) - { - case AV_CODEC_ID_H264: -- { -- switch(hints.profile) -- { -- case FF_PROFILE_H264_BASELINE: -- // (role name) video_decoder.avc -- // H.264 Baseline profile -- decoder_name = OMX_H264BASE_DECODER; -- break; -- case FF_PROFILE_H264_MAIN: -- // (role name) video_decoder.avc -- // H.264 Main profile -- decoder_name = OMX_H264MAIN_DECODER; -- break; -- case FF_PROFILE_H264_HIGH: -- // (role name) video_decoder.avc -- // H.264 Main profile -- decoder_name = OMX_H264HIGH_DECODER; -- break; -- default: -- return false; -- break; -- } -- } -+ // H.264 -+ m_codingType = OMX_VIDEO_CodingAVC; -+ m_pFormatName = "omx-h264"; - break; -+ case AV_CODEC_ID_H263: - case AV_CODEC_ID_MPEG4: -- // (role name) video_decoder.mpeg4 -- // MPEG-4, DivX 4/5 and Xvid compatible -- decoder_name = OMX_MPEG4_DECODER; -- break; -- /* -- TODO: what mpeg4 formats are "ext" ???? -- case NvxStreamType_MPEG4Ext: -- // (role name) video_decoder.mpeg4 - // MPEG-4, DivX 4/5 and Xvid compatible -- decoder_name = OMX_MPEG4EXT_DECODER; -+ m_codingType = OMX_VIDEO_CodingMPEG4; - m_pFormatName = "omx-mpeg4"; - break; -- */ -+ case AV_CODEC_ID_MPEG1VIDEO: - case AV_CODEC_ID_MPEG2VIDEO: -- // (role name) video_decoder.mpeg2 - // MPEG-2 -- decoder_name = OMX_MPEG2V_DECODER; -+ m_codingType = OMX_VIDEO_CodingMPEG2; -+ m_pFormatName = "omx-mpeg2"; -+ break; -+ case AV_CODEC_ID_VP6: -+ // this form is encoded upside down -+ // fall through -+ case AV_CODEC_ID_VP6F: -+ case AV_CODEC_ID_VP6A: -+ // VP6 -+ m_codingType = OMX_VIDEO_CodingVP6; -+ m_pFormatName = "omx-vp6"; -+ break; -+ case AV_CODEC_ID_VP8: -+ // VP8 -+ m_codingType = OMX_VIDEO_CodingVP8; -+ m_pFormatName = "omx-vp8"; -+ break; -+ case AV_CODEC_ID_THEORA: -+ // theora -+ m_codingType = OMX_VIDEO_CodingTheora; -+ m_pFormatName = "omx-theora"; -+ break; -+ case AV_CODEC_ID_MJPEG: -+ case AV_CODEC_ID_MJPEGB: -+ // mjpg -+ m_codingType = OMX_VIDEO_CodingMJPEG; -+ m_pFormatName = "omx-mjpg"; - break; - case AV_CODEC_ID_VC1: -- // (role name) video_decoder.vc1 -+ case AV_CODEC_ID_WMV3: - // VC-1, WMV9 -- decoder_name = OMX_VC1_DECODER; -- break; -+ m_codingType = OMX_VIDEO_CodingWMV; -+ m_pFormatName = "omx-vc1"; -+ break; - default: -+ CLog::Log(LOGERROR, "%s::%s : Video codec unknown: %x", CLASSNAME, __func__, hints.codec); - return false; - break; - } - - // initialize OpenMAX. -- if (!Initialize(decoder_name)) -+ if (!m_omx_decoder.Initialize("OMX.broadcom.video_decode", OMX_IndexParamVideoInit)) - { -+ CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize", CLASSNAME, __func__); - return false; - } - -- // TODO: Find component from role name. -- // Get the port information. This will obtain information about the -- // number of ports and index of the first port. -- OMX_PORT_PARAM_TYPE port_param; -- OMX_INIT_STRUCTURE(port_param); -- omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamVideoInit, &port_param); -- if (omx_err) -+ omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle); -+ if (omx_err != OMX_ErrorNone) - { -- Deinitialize(); -+ CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err); - return false; - } -- m_omx_input_port = port_param.nStartPortNumber; -- m_omx_output_port = m_omx_input_port + 1; -- #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, -- "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x)\n", -- CLASSNAME, __func__, m_omx_decoder, m_omx_input_port, m_omx_output_port); -- #endif - -- // TODO: Set role for the component because components could have multiple roles. -- //QueryCodec(); -+ OMX_VIDEO_PARAM_PORTFORMATTYPE formatType; -+ OMX_INIT_STRUCTURE(formatType); -+ formatType.nPortIndex = m_omx_decoder.GetInputPort(); -+ formatType.eCompressionFormat = m_codingType; ++ // replace passed in number of bits with correct ones ++ src_bits = format_to_bits(src_fmt); ++ dst_bits = format_to_bits(dst_fmt); + -+ omx_err = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType); -+ if (omx_err != OMX_ErrorNone) ++ m_dst_chan_layout = dst_chan_layout; ++ m_dst_channels = dst_channels; ++ m_dst_rate = dst_rate; ++ m_dst_fmt = dst_fmt; ++ m_dst_bits = dst_bits; ++ m_src_chan_layout = src_chan_layout; ++ m_src_channels = src_channels; ++ m_src_rate = src_rate; ++ m_src_fmt = src_fmt; ++ m_src_bits = src_bits; ++ ++ if (m_dst_chan_layout == 0) ++ m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); ++ if (m_src_chan_layout == 0) ++ m_src_chan_layout = av_get_default_channel_layout(m_src_channels); ++ ++ OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix; ++ OMX_INIT_STRUCTURE(mix); ++ ++ assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64); ++ ++ LOGTIME(1); ++// this code is just uses ffmpeg to produce the 8x8 mixing matrix ++{ ++ // dummy sample rate and format, as we only care about channel mapping ++ SwrContext *m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000, ++ m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL); ++ if (!m_pContext) + { -+ CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ CLog::Log(LOGERROR, "CActiveAEResample::Init - create context failed"); + return false; + } -+ OMX_PARAM_PORTDEFINITIONTYPE portParam; -+ OMX_INIT_STRUCTURE(portParam); -+ portParam.nPortIndex = m_omx_decoder.GetInputPort(); -+ -+ omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam); -+ if (omx_err != OMX_ErrorNone) ++ // tell resampler to clamp float values ++ // not required for sink stage (remapLayout == true) ++ if (!remapLayout && normalize) + { -+ CLog::Log(LOGERROR, "%s::%s error OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; ++ av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0); + } + -+ portParam.nPortIndex = m_omx_decoder.GetInputPort(); -+ portParam.nBufferCountActual = 20; -+ portParam.format.video.nFrameWidth = m_decoded_width; -+ portParam.format.video.nFrameHeight = m_decoded_height; -+ -+ omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam); -+ if (omx_err != OMX_ErrorNone) ++ if (remapLayout) + { -+ CLog::Log(LOGERROR, "%s::%s error OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ // request portsettingschanged on aspect ratio change -+ OMX_CONFIG_REQUESTCALLBACKTYPE notifications; -+ OMX_INIT_STRUCTURE(notifications); -+ notifications.nPortIndex = m_omx_decoder.GetOutputPort(); -+ notifications.nIndex = OMX_IndexParamBrcmPixelAspectRatio; -+ notifications.bEnable = OMX_TRUE; -+ -+ omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexConfigRequestCallback, ¬ifications); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s OMX_IndexConfigRequestCallback error (0%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ if (NaluFormatStartCodes(hints.codec, (uint8_t *)hints.extradata, hints.extrasize)) -+ { -+ OMX_NALSTREAMFORMATTYPE nalStreamFormat; -+ OMX_INIT_STRUCTURE(nalStreamFormat); -+ nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort(); -+ nalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes; -+ -+ omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat); -+ if (omx_err != OMX_ErrorNone) ++ // one-to-one mapping of channels ++ // remapLayout is the layout of the sink, if the channel is in our src layout ++ // the channel is mapped by setting coef 1.0 ++ double m_rematrix[AE_CH_MAX][AE_CH_MAX]; ++ memset(m_rematrix, 0, sizeof(m_rematrix)); ++ m_dst_chan_layout = 0; ++ for (unsigned int out=0; outCount(); out++) + { -+ CLog::Log(LOGERROR, "%s::%s OMX_IndexParamNalStreamFormatSelect error (0%08x)", CLASSNAME, __func__, omx_err); ++ m_dst_chan_layout += (uint64_t) (1 << out); ++ int idx = GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout); ++ if (idx >= 0) ++ { ++ m_rematrix[out][idx] = 1.0; ++ } ++ } ++ ++ av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0); ++ av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0); ++ ++ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0) ++ { ++ CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed"); + return false; + } + } - -- // Component will be in OMX_StateLoaded now so we can alloc omx input/output buffers. -- // we can only alloc them in OMX_StateLoaded state or if the component port is disabled - // Alloc buffers for the omx input port. -- omx_err = AllocOMXInputBuffers(); -- if (omx_err) -+ omx_err = m_omx_decoder.AllocInputBuffers(); -+ if (omx_err != OMX_ErrorNone) - { -- Deinitialize(); -+ CLog::Log(LOGERROR, "%s::%s AllocInputBuffers error (0%08x)", CLASSNAME, __func__, omx_err); - return false; - } -- // Alloc buffers for the omx output port. -- m_egl_display = g_Windowing.GetEGLDisplay(); -- m_egl_context = g_Windowing.GetEGLContext(); -- omx_err = AllocOMXOutputBuffers(); -- if (omx_err) ++ // stereo upmix ++ else if (upmix && m_src_channels == 2 && m_dst_channels > 2) ++ { ++ double m_rematrix[AE_CH_MAX][AE_CH_MAX]; ++ memset(m_rematrix, 0, sizeof(m_rematrix)); ++ for (int out=0; out 0 && extradata != NULL) - { -- OMX_ERRORTYPE omx_err; -+ OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(); - -- // blow all but the last ready video frame -- pthread_mutex_lock(&m_omx_output_mutex); -- while (m_omx_output_ready.size() > 1) ++ if (!m_omx_mixer.Initialize("OMX.broadcom.audio_mixer", OMX_IndexParamAudioInit)) ++ CLog::Log(LOGERROR, "%s::%s - m_omx_mixer.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(3); ++ ++ // audio_mixer only supports up to 192kHz, however as long as ratio of samplerates remains the same we can lie ++ while (src_rate > 192000 || dst_rate > 192000) ++ src_rate >>= 1, dst_rate >>= 1; ++ ++ OMX_INIT_STRUCTURE(m_pcm_input); ++ m_pcm_input.nPortIndex = m_omx_mixer.GetInputPort(); ++ m_pcm_input.eNumData = OMX_NumericalDataSigned; ++ m_pcm_input.eEndian = OMX_EndianLittle; ++ m_pcm_input.bInterleaved = OMX_TRUE; ++ m_pcm_input.nBitPerSample = m_src_bits; ++ // 0x8000 = float, 0x10000 = planar ++ uint32_t flags = 0; ++ if (m_src_fmt == AV_SAMPLE_FMT_FLT || m_src_fmt == AV_SAMPLE_FMT_FLTP) ++ flags |= 0x8000; ++ if (m_src_fmt >= AV_SAMPLE_FMT_U8P) ++ flags |= 0x10000; ++ m_pcm_input.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags; ++ m_pcm_input.nChannels = src_channels; ++ m_pcm_input.nSamplingRate = src_rate; ++ ++ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer in SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ OMX_INIT_STRUCTURE(m_pcm_output); ++ m_pcm_output.nPortIndex = m_omx_mixer.GetOutputPort(); ++ m_pcm_output.eNumData = OMX_NumericalDataSigned; ++ m_pcm_output.eEndian = OMX_EndianLittle; ++ m_pcm_output.bInterleaved = OMX_TRUE; ++ m_pcm_output.nBitPerSample = m_dst_bits; ++ flags = 0; ++ if (m_dst_fmt == AV_SAMPLE_FMT_FLT || m_dst_fmt == AV_SAMPLE_FMT_FLTP) ++ flags |= 0x8000; ++ if (m_dst_fmt >= AV_SAMPLE_FMT_U8P) ++ flags |= 0x10000; ++ m_pcm_output.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags; ++ m_pcm_output.nChannels = dst_channels; ++ m_pcm_output.nSamplingRate = dst_rate; ++ ++ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer out SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(4); ++ ++ mix.nPortIndex = m_omx_mixer.GetInputPort(); ++ omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix); ++ if (omx_err != OMX_ErrorNone) ++ { ++ CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n", ++ CLASSNAME, __func__, omx_err); ++ return false; ++ } ++ ++ // set up the number/size of buffers for decoder input ++ OMX_PARAM_PORTDEFINITIONTYPE port_param; ++ OMX_INIT_STRUCTURE(port_param); ++ port_param.nPortIndex = m_omx_mixer.GetInputPort(); ++ ++ omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1); ++ port_param.nBufferSize = BUFFERSIZE; ++ ++ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(5); ++ ++ omx_err = m_omx_mixer.AllocInputBuffers(); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(6); ++ ++ // set up the number/size of buffers for decoder output ++ OMX_INIT_STRUCTURE(port_param); ++ port_param.nPortIndex = m_omx_mixer.GetOutputPort(); ++ ++ omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1); ++ port_param.nBufferSize = BUFFERSIZE; ++ ++ omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(7); ++ ++ omx_err = m_omx_mixer.AllocOutputBuffers(); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(8); ++ ++ omx_err = m_omx_mixer.SetStateForComponent(OMX_StateExecuting); ++ if (omx_err != OMX_ErrorNone) ++ CLog::Log(LOGERROR, "%s:%s - m_omx_mixer OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ ++ LOGTIME(9); ++ ++ m_Initialized = true; ++ ++ return true; ++} ++ ++ ++static void copy_planes(uint8_t **dst_buffer, int d_pitch, int d_planes, int d_samplesize, int offset, uint8_t *src_buffer, int src_samples) ++{ ++ int planesize = src_samples * d_samplesize / d_planes; ++ for (int i=0; i < d_planes; i++) ++ memcpy(dst_buffer[i] + offset * d_pitch, src_buffer + i * planesize, planesize); ++} ++ ++int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio) ++{ ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s samples:%d->%d (%.2f)", CLASSNAME, __func__, src_samples, dst_samples, ratio); ++ #endif ++ if (!m_Initialized) ++ return 0; ++ OMX_ERRORTYPE omx_err = OMX_ErrorNone; ++ ++ const int s_planes = m_src_fmt >= AV_SAMPLE_FMT_U8P ? m_src_channels : 1; ++ const int d_planes = m_dst_fmt >= AV_SAMPLE_FMT_U8P ? m_dst_channels : 1; ++ const int s_chans = m_src_fmt >= AV_SAMPLE_FMT_U8P ? 1 : m_src_channels; ++ const int d_chans = m_dst_fmt >= AV_SAMPLE_FMT_U8P ? 1 : m_dst_channels; ++ const int s_pitch = s_chans * m_src_bits >> 3; ++ const int d_pitch = d_chans * m_dst_bits >> 3; ++ ++ const int s_samplesize = m_src_channels * m_src_bits >> 3; ++ const int d_samplesize = m_dst_channels * m_dst_bits >> 3; ++ const int max_src_samples = BUFFERSIZE / s_samplesize; ++ const int max_dst_samples = (long long)(BUFFERSIZE / d_samplesize) * m_src_rate / (m_dst_rate + m_src_rate-1); ++ ++ int sent = 0; ++ int received = 0; ++ ++ if (m_encoded_buffer && m_encoded_buffer->nFilledLen) ++ { ++ int samples_available = m_encoded_buffer->nFilledLen / d_samplesize - m_encoded_buffer->nOffset; ++ int samples = std::min(samples_available, dst_samples - received); ++ copy_planes(dst_buffer, d_pitch, d_planes, d_samplesize, received, (uint8_t *)m_encoded_buffer->pBuffer + m_encoded_buffer->nOffset * d_pitch, samples); ++ received += samples; ++ samples_available -= samples; ++ if (samples_available > 0) ++ m_encoded_buffer->nOffset += samples; ++ else ++ m_encoded_buffer = NULL; ++ } ++ assert(!m_encoded_buffer); ++ while (sent < src_samples) ++ { ++ OMX_BUFFERHEADERTYPE *omx_buffer = NULL; ++ ++ omx_buffer = m_omx_mixer.GetInputBuffer(1000); + if (omx_buffer == NULL) - { -- m_dts_queue.pop(); -- OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_output_ready.front()->omx_buffer; -- m_omx_output_ready.pop(); -- // return the omx buffer back to OpenMax to fill. -- omx_err = OMX_FillThisBuffer(m_omx_decoder, omx_buffer); -- if (omx_err) -- CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -+ CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err); + return false; - } -- pthread_mutex_unlock(&m_omx_output_mutex); - -- #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)\n", -- CLASSNAME, __func__, m_drop_state); -- #endif ++ ++ int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent); ++ + omx_buffer->nOffset = 0; -+ omx_buffer->nFilledLen = extrasize; -+ if (omx_buffer->nFilledLen > omx_buffer->nAllocLen) ++ omx_buffer->nFlags = OMX_BUFFERFLAG_EOS; ++ omx_buffer->nFilledLen = send * s_samplesize; ++ ++ assert(omx_buffer->nFilledLen > 0 && omx_buffer->nFilledLen <= omx_buffer->nAllocLen); ++ ++ if (omx_buffer->nFilledLen) + { -+ CLog::Log(LOGERROR, "%s::%s - omx_buffer->nFilledLen > omx_buffer->nAllocLen", CLASSNAME, __func__); ++ int planesize = omx_buffer->nFilledLen / s_planes; ++ for (int i=0; i < s_planes; i++) ++ memcpy((uint8_t *)omx_buffer->pBuffer + i * planesize, src_buffer[i] + sent * s_pitch, planesize); ++ sent += send; ++ } ++ ++ omx_err = m_omx_mixer.EmptyThisBuffer(omx_buffer); ++ if (omx_err != OMX_ErrorNone) ++ { ++ CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err); + return false; + } + -+ memcpy((unsigned char *)omx_buffer->pBuffer, extradata, omx_buffer->nFilledLen); -+ omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME; ++ m_encoded_buffer = m_omx_mixer.GetOutputBuffer(); + -+//CLog::Log(LOGINFO, "%s::%s - Empty(%d,%x)", CLASSNAME, __func__, omx_buffer->nFilledLen, omx_buffer->nFlags); CLog::MemDump((char *)omx_buffer->pBuffer, std::min(64U, omx_buffer->nFilledLen)); -+ omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); -+ if (omx_err != OMX_ErrorNone) ++ if (!m_encoded_buffer) + { -+ CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err); ++ CLog::Log(LOGERROR, "%s::%s no output buffer", CLASSNAME, __func__); + return false; + } - } -+ return true; - } - --int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) -+bool COpenMaxVideo::NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize) -+{ -+ switch(codec) -+ { -+ case AV_CODEC_ID_H264: -+ if (extrasize < 7 || extradata == NULL) -+ return true; -+ // valid avcC atom data always starts with the value 1 (version), otherwise annexb -+ else if ( *extradata != 1 ) -+ return true; -+ default: break; -+ } -+ return false; -+} + -+bool COpenMaxVideo::PortSettingsChanged() - { -- if (pData) -+ OMX_ERRORTYPE omx_err = OMX_ErrorNone; -+ -+ if (m_port_settings_changed) -+ { -+ m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true); -+ } -+ -+ OMX_PARAM_PORTDEFINITIONTYPE port_def; -+ OMX_INIT_STRUCTURE(port_def); -+ port_def.nPortIndex = m_omx_decoder.GetOutputPort(); -+ omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ OMX_CONFIG_POINTTYPE pixel_aspect; -+ OMX_INIT_STRUCTURE(pixel_aspect); -+ pixel_aspect.nPortIndex = m_omx_decoder.GetOutputPort(); -+ omx_err = m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio, &pixel_aspect); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ if (m_port_settings_changed) - { -- int demuxer_bytes = iSize; -- uint8_t *demuxer_content = pData; -+ m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true); -+ return true; -+ } -+ -+ // convert in stripes -+ port_def.format.video.nSliceHeight = 16; -+ port_def.format.video.nStride = 0; -+ -+ omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ OMX_CALLBACKTYPE callbacks = { NULL, NULL, DecoderFillBufferDoneCallback }; -+ if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit, &callbacks)) -+ { -+ CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__); -+ return false; -+ } -+ -+ OMX_CONFIG_PORTBOOLEANTYPE discardMode; -+ OMX_INIT_STRUCTURE(discardMode); -+ discardMode.nPortIndex = m_omx_egl_render.GetInputPort(); -+ discardMode.bEnabled = OMX_FALSE; -+ omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamBrcmVideoEGLRenderDiscardMode, &discardMode); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - error m_omx_egl_render.SetParameter(OMX_IndexParamBrcmVideoEGLRenderDiscardMode) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ m_omx_egl_render.ResetEos(); -+ -+ CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__, -+ port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight, -+ port_def.format.video.xFramerate / (float)(1<<16), 0,0); -+ -+ m_omx_tunnel.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort()); -+ -+ omx_err = m_omx_tunnel.Establish(); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ // Obtain the information about the output port. -+ OMX_PARAM_PORTDEFINITIONTYPE port_format; -+ OMX_INIT_STRUCTURE(port_format); -+ port_format.nPortIndex = m_omx_egl_render.GetOutputPort(); -+ omx_err = m_omx_egl_render.GetParameter(OMX_IndexParamPortDefinition, &port_format); -+ if (omx_err != OMX_ErrorNone) -+ CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.GetParameter OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ -+ port_format.nBufferCountActual = m_egl_buffer_count; -+ omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamPortDefinition, &port_format); -+ if (omx_err != OMX_ErrorNone) -+ CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.SetParameter OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ -+ #if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, -+ "%s::%s (1) - oport(%d), nFrameWidth(%u), nFrameHeight(%u), nStride(%x), nBufferCountMin(%u), nBufferCountActual(%u), nBufferSize(%u)", -+ CLASSNAME, __func__, m_omx_egl_render.GetOutputPort(), -+ port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride, -+ port_format.nBufferCountMin, port_format.nBufferCountActual, port_format.nBufferSize); -+ #endif -+ - -- // we need to queue then de-queue the demux packet, seems silly but -- // omx might not have a omx input buffer avaliable when we are called -- // and we must store the demuxer packet and try again later. -+ omx_err = m_omx_egl_render.EnablePort(m_omx_egl_render.GetOutputPort(), false); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.EnablePort omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ if (!AllocOMXOutputBuffers()) -+ { -+ CLog::Log(LOGERROR, "%s::%s - AllocOMXOutputBuffers failed", CLASSNAME, __func__); -+ return false; -+ } -+ -+ omx_err = m_omx_egl_render.WaitForCommand(OMX_CommandPortEnable, m_omx_egl_render.GetOutputPort()); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.WaitForCommand(OMX_CommandPortEnable) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ assert(m_omx_output_busy.empty()); -+ assert(m_omx_output_ready.empty()); -+ -+ omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ omx_err = PrimeFillBuffers(); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.PrimeFillBuffers omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ m_port_settings_changed = true; -+ return true; -+} -+ -+ -+int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) -+{ -+ #if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f demux_queue(%d) dts_queue(%d) ready_queue(%d) busy_queue(%d)", -+ CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_demux_queue.size(), m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy.size()); -+ #endif -+ -+ OMX_ERRORTYPE omx_err; -+ unsigned int demuxer_bytes = 0; -+ uint8_t *demuxer_content = NULL; -+ -+ // we need to queue then de-queue the demux packet, seems silly but -+ // omx might not have a omx input buffer available when we are called -+ // and we must store the demuxer packet and try again later. -+ if (pData && m_demux_queue.empty() && m_omx_decoder.GetInputBufferSpace() >= (unsigned int)iSize) -+ { -+ demuxer_bytes = iSize; -+ demuxer_content = pData; -+ } -+ else if (pData && iSize) -+ { - omx_demux_packet demux_packet; - demux_packet.dts = dts; - demux_packet.pts = pts; -- -- demux_packet.size = demuxer_bytes; -- demux_packet.buff = new OMX_U8[demuxer_bytes]; -- memcpy(demux_packet.buff, demuxer_content, demuxer_bytes); -+ demux_packet.size = iSize; -+ demux_packet.buff = new OMX_U8[iSize]; -+ memcpy(demux_packet.buff, pData, iSize); - m_demux_queue.push(demux_packet); -+ } - -- // we can look at m_omx_input_avaliable.empty without needing to lock/unlock -+ OMX_U8 *buffer_to_free = NULL; -+ while (1) -+ { - // try to send any/all demux packets to omx decoder. -- while (!m_omx_input_avaliable.empty() && !m_demux_queue.empty() ) -+ if (!demuxer_bytes && !m_demux_queue.empty()) - { -- OMX_ERRORTYPE omx_err; -- OMX_BUFFERHEADERTYPE* omx_buffer; -- -- demux_packet = m_demux_queue.front(); -- m_demux_queue.pop(); -- // need to lock here to retreve an input buffer and pop the queue -- pthread_mutex_lock(&m_omx_input_mutex); -- omx_buffer = m_omx_input_avaliable.front(); -- m_omx_input_avaliable.pop(); -- pthread_mutex_unlock(&m_omx_input_mutex); -- -- // delete the previous demuxer buffer -- delete [] omx_buffer->pBuffer; -- // setup a new omx_buffer. -- omx_buffer->nFlags = m_omx_input_eos ? OMX_BUFFERFLAG_EOS : 0; -+ omx_demux_packet &demux_packet = m_demux_queue.front(); -+ if (m_omx_decoder.GetInputBufferSpace() >= (unsigned int)demux_packet.size) -+ { -+ // need to lock here to retrieve an input buffer and pop the queue -+ m_demux_queue.pop(); -+ demuxer_bytes = (unsigned int)demux_packet.size; -+ demuxer_content = demux_packet.buff; -+ buffer_to_free = demux_packet.buff; -+ dts = demux_packet.dts; -+ pts = demux_packet.pts; -+ } -+ } -+ -+ if (demuxer_content) -+ { -+ // 500ms timeout -+ OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(500); -+ if (omx_buffer == NULL) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_decoder.GetInputBuffer timeout", CLASSNAME, __func__); -+ return VC_ERROR; -+ } -+ #if defined(OMX_DEBUG_VERBOSE) -+ //CLog::Log(LOGDEBUG, "%s::%s - omx_buffer=%p", CLASSNAME, __func__, omx_buffer); -+ #endif -+ omx_buffer->nFlags = 0; - omx_buffer->nOffset = 0; -- omx_buffer->pBuffer = demux_packet.buff; -- omx_buffer->nAllocLen = demux_packet.size; -- omx_buffer->nFilledLen = demux_packet.size; -- omx_buffer->nTimeStamp = (demux_packet.pts == DVD_NOPTS_VALUE) ? 0 : demux_packet.pts * 1000.0; // in microseconds; -+ -+ omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes; -+ omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts); - omx_buffer->pAppPrivate = omx_buffer; -- omx_buffer->nInputPortIndex = m_omx_input_port; -+ memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen); - -- #if defined(OMX_DEBUG_EMPTYBUFFERDONE) -- CLog::Log(LOGDEBUG, -- "%s::%s - feeding decoder, omx_buffer->pBuffer(0x%p), demuxer_bytes(%d)\n", -- CLASSNAME, __func__, omx_buffer->pBuffer, demuxer_bytes); -- #endif -- // Give this omx_buffer to OpenMax to be decoded. -- omx_err = OMX_EmptyThisBuffer(m_omx_decoder, omx_buffer); -- if (omx_err) -+ demuxer_bytes -= omx_buffer->nFilledLen; -+ demuxer_content += omx_buffer->nFilledLen; -+ -+ if (demuxer_bytes == 0) -+ omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; -+ if (pts == DVD_NOPTS_VALUE) -+ omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN; -+ if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored) -+ omx_buffer->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; -+ -+#if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x", -+ CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags); -+#endif -+ -+ omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); -+ if (omx_err != OMX_ErrorNone) - { -- CLog::Log(LOGDEBUG, -- "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", -- CLASSNAME, __func__, omx_err); -+ CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err); - return VC_ERROR; - } -- // only push if we are successful with feeding OMX_EmptyThisBuffer -- m_dts_queue.push(demux_packet.dts); -- -- // if m_omx_input_avaliable and/or demux_queue are now empty, -- // wait up to 20ms for OpenMax to consume a demux packet -- if (m_omx_input_avaliable.empty() || m_demux_queue.empty()) -- m_input_consumed_event.WaitMSec(1); -+ if (demuxer_bytes == 0) -+ { -+#ifdef DTS_QUEUE -+ // only push if we are successful with feeding OMX_EmptyThisBuffer -+ m_dts_queue.push(dts); -+ assert(m_dts_queue.size() < 32); -+#endif -+ if (buffer_to_free) -+ { -+ delete [] buffer_to_free; -+ buffer_to_free = NULL; -+ demuxer_content = NULL; -+ continue; -+ } -+ } -+ } -+ omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, 0); -+ if (omx_err == OMX_ErrorNone) -+ { -+ if (!PortSettingsChanged()) -+ { -+ CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return VC_ERROR; -+ } -+ } -+ else if (omx_err != OMX_ErrorTimeout) -+ { -+ CLog::Log(LOGERROR, "%s::%s - video not supported omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return VC_ERROR; - } -- if (m_omx_input_avaliable.empty() && !m_demux_queue.empty()) -- m_input_consumed_event.WaitMSec(1); -- -- #if defined(OMX_DEBUG_VERBOSE) -- if (m_omx_input_avaliable.empty()) -- CLog::Log(LOGDEBUG, -- "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d)\n", -- CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes); -- #endif -+ omx_err = m_omx_decoder.WaitForEvent(OMX_EventParamOrConfigChanged, 0); -+ if (omx_err == OMX_ErrorNone) -+ { -+ if (!PortSettingsChanged()) -+ { -+ CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged (EventParamOrConfigChanged) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return VC_ERROR; -+ } -+ } -+ else if (omx_err == OMX_ErrorStreamCorrupt) -+ { -+ CLog::Log(LOGERROR, "%s::%s - video not supported 2 omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return VC_ERROR; -+ } -+ if (!demuxer_bytes) -+ break; - } - -+#if defined(OMX_DEBUG_VERBOSE) -+ if (!m_omx_decoder.GetInputBufferSpace()) -+ CLog::Log(LOGDEBUG, -+ "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d) m_dts_queue.size(%d)", -+ CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes, m_dts_queue.size()); -+ #endif -+ - if (m_omx_output_ready.empty()) -+ { -+ //CLog::Log(LOGDEBUG, "%s::%s - empty: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size()); - return VC_BUFFER; -+ } - -- return VC_PICTURE | VC_BUFFER; -+ //CLog::Log(LOGDEBUG, "%s::%s - full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size()); -+ return VC_PICTURE; - } - - void COpenMaxVideo::Reset(void) - { - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); -+ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - #endif --/* -- // only reset OpenMax decoder if it's running -- if (m_omx_decoder_state == OMX_StateExecuting) -+ m_omx_egl_render.FlushAll(); -+ m_omx_decoder.FlushAll(); -+ // blow all ready video frames -+ while (!m_omx_output_ready.empty()) - { -- OMX_ERRORTYPE omx_err; -- -- omx_err = StopDecoder(); -- // Alloc OpenMax input buffers. -- omx_err = AllocOMXInputBuffers(); -- // Alloc OpenMax output buffers. -- omx_err = AllocOMXOutputBuffers(); -- -- omx_err = StartDecoder(); -+ pthread_mutex_lock(&m_omx_output_mutex); -+ COpenMaxVideoBuffer *pic = m_omx_output_ready.front(); -+ m_omx_output_ready.pop(); -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ // return the omx buffer back to OpenMax to fill. -+ ReturnOpenMaxBuffer(pic); - } --*/ -- ::Sleep(100); -+#ifdef DTS_QUEUE -+ while (!m_dts_queue.empty()) -+ m_dts_queue.pop(); -+#endif -+ -+ while (!m_demux_queue.empty()) -+ m_demux_queue.pop(); - } - --bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) -+ -+OMX_ERRORTYPE COpenMaxVideo::ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer) - { -- while (m_omx_output_busy.size() > 1) -+ OMX_ERRORTYPE omx_err = OMX_ErrorNone; -+#if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s %p (%d)", CLASSNAME, __func__, buffer, m_omx_output_busy.size()); -+#endif -+ bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS; -+ if (!done) - { -- // fetch a output buffer and pop it off the busy list -- pthread_mutex_lock(&m_omx_output_mutex); -- OpenMaxVideoBuffer *buffer = m_omx_output_busy.front(); -- m_omx_output_busy.pop(); -- pthread_mutex_unlock(&m_omx_output_mutex); -+ // return the omx buffer back to OpenMax to fill. -+ buffer->omx_buffer->nFlags = 0; -+ buffer->omx_buffer->nFilledLen = 0; - -- bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS; -- if (!done) -- { -- // return the omx buffer back to OpenMax to fill. -- OMX_ERRORTYPE omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer); -- if (omx_err) -- CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -- } -+ assert(buffer->omx_buffer->nOutputPortIndex == m_omx_egl_render.GetOutputPort()); -+#if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s FillThisBuffer(%p) %p->%ld", CLASSNAME, __func__, buffer, buffer->omx_buffer, buffer->m_refs); -+#endif -+ OMX_ERRORTYPE omx_err = m_omx_egl_render.FillThisBuffer(buffer->omx_buffer); -+ -+ if (omx_err) -+ CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)", CLASSNAME, __func__, omx_err); - } -+ return omx_err; -+} -+ -+void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer) -+{ -+ // remove from busy list -+ pthread_mutex_lock(&m_omx_output_mutex); -+ m_omx_output_busy.erase(std::remove(m_omx_output_busy.begin(), m_omx_output_busy.end(), buffer), m_omx_output_busy.end()); -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ ReturnOpenMaxBuffer(buffer); -+} -+ -+bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) -+{ -+ //CLog::Log(LOGDEBUG, "%s::%s - m_omx_output_busy.size()=%d m_omx_output_ready.size()=%d", CLASSNAME, __func__, m_omx_output_busy.size(), m_omx_output_ready.size()); -+ //CLog::Log(LOGDEBUG, "%s::%s - full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size()); - - if (!m_omx_output_ready.empty()) - { -- OpenMaxVideoBuffer *buffer; -+ COpenMaxVideoBuffer *buffer; - // fetch a output buffer and pop it off the ready list - pthread_mutex_lock(&m_omx_output_mutex); - buffer = m_omx_output_ready.front(); - m_omx_output_ready.pop(); -- m_omx_output_busy.push(buffer); -+ m_omx_output_busy.push_back(buffer); - pthread_mutex_unlock(&m_omx_output_mutex); - -+ memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture); - pDvdVideoPicture->dts = DVD_NOPTS_VALUE; - pDvdVideoPicture->pts = DVD_NOPTS_VALUE; - pDvdVideoPicture->format = RENDER_FMT_OMXEGL; -- pDvdVideoPicture->openMax = this; - pDvdVideoPicture->openMaxBuffer = buffer; -- -+ pDvdVideoPicture->color_range = 0; -+ pDvdVideoPicture->color_matrix = 4; -+ pDvdVideoPicture->iWidth = m_decoded_width; -+ pDvdVideoPicture->iHeight = m_decoded_height; -+ pDvdVideoPicture->iDisplayWidth = m_decoded_width; -+ pDvdVideoPicture->iDisplayHeight = m_decoded_height; -+ -+#ifdef DTS_QUEUE - if (!m_dts_queue.empty()) - { - pDvdVideoPicture->dts = m_dts_queue.front(); - m_dts_queue.pop(); - } -+#endif - // nTimeStamp is in microseconds -- pDvdVideoPicture->pts = (buffer->omx_buffer->nTimeStamp == 0) ? DVD_NOPTS_VALUE : (double)buffer->omx_buffer->nTimeStamp / 1000.0; -+ double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp); -+ pDvdVideoPicture->pts = (ts == 0) ? DVD_NOPTS_VALUE : ts; -+ pDvdVideoPicture->openMaxBuffer->Acquire(); -+ pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; -+ if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT) -+ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; -+#if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__, -+ pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6, -+ pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id); -+#endif - } -- #if defined(OMX_DEBUG_VERBOSE) - else - { -- CLog::Log(LOGDEBUG, "%s::%s - called but m_omx_output_ready is empty\n", -- CLASSNAME, __func__); -+ CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__); -+ return false; - } -- #endif -- -- pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; -- pDvdVideoPicture->iFlags |= m_drop_state ? DVP_FLAG_DROPPED : 0; -- - return true; - } - -- --// DecoderEmptyBufferDone -- OpenMax input buffer has been emptied --OMX_ERRORTYPE COpenMaxVideo::DecoderEmptyBufferDone( -- OMX_HANDLETYPE hComponent, -- OMX_PTR pAppData, -- OMX_BUFFERHEADERTYPE* pBuffer) -+bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture) - { -- COpenMaxVideo *ctx = static_cast(pAppData); --/* -- #if defined(OMX_DEBUG_EMPTYBUFFERDONE) -- CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n", -- CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0); -- #endif --*/ -- // queue free input buffer to avaliable list. -- pthread_mutex_lock(&ctx->m_omx_input_mutex); -- ctx->m_omx_input_avaliable.push(pBuffer); -- ctx->m_input_consumed_event.Set(); -- pthread_mutex_unlock(&ctx->m_omx_input_mutex); -- -- return OMX_ErrorNone; -+#if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s - %p", CLASSNAME, __func__, pDvdVideoPicture->openMaxBuffer); -+#endif -+ if (pDvdVideoPicture->format == RENDER_FMT_OMXEGL) -+ pDvdVideoPicture->openMaxBuffer->Release(); -+ memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture); -+ return true; - } - --// DecoderFillBufferDone -- OpenMax output buffer has been filled -+ // DecoderFillBufferDone -- OpenMax output buffer has been filled - OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone( - OMX_HANDLETYPE hComponent, -- OMX_PTR pAppData, - OMX_BUFFERHEADERTYPE* pBuffer) - { -- COpenMaxVideo *ctx = static_cast(pAppData); -- OpenMaxVideoBuffer *buffer = (OpenMaxVideoBuffer*)pBuffer->pAppPrivate; -+ COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate; - -- #if defined(OMX_DEBUG_FILLBUFFERDONE) -- CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n", -- CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0); -+ #if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f", -+ CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6); - #endif - -- if (!ctx->m_portChanging) -- { -- // queue output omx buffer to ready list. -- pthread_mutex_lock(&ctx->m_omx_output_mutex); -- ctx->m_omx_output_ready.push(buffer); -- pthread_mutex_unlock(&ctx->m_omx_output_mutex); -- } -+ // queue output omx buffer to ready list. -+ pthread_mutex_lock(&m_omx_output_mutex); -+ m_omx_output_ready.push(buffer); -+ pthread_mutex_unlock(&m_omx_output_mutex); - - return OMX_ErrorNone; - } - --void COpenMaxVideo::QueryCodec(void) --{ -- OMX_ERRORTYPE omx_err = OMX_ErrorNone; -- OMX_VIDEO_PARAM_PROFILELEVELTYPE port_param; -- OMX_INIT_STRUCTURE(port_param); -- -- port_param.nPortIndex = m_omx_input_port; -- -- for (port_param.nProfileIndex = 0;; port_param.nProfileIndex++) -- { -- omx_err = OMX_GetParameter(m_omx_decoder, -- OMX_IndexParamVideoProfileLevelQuerySupported, &port_param); -- if (omx_err) -- break; -- -- omx_codec_capability omx_capability; -- omx_capability.level = port_param.eLevel; -- omx_capability.profile = port_param.eProfile; -- m_omx_decoder_capabilities.push_back(omx_capability); -- } --} -- - OMX_ERRORTYPE COpenMaxVideo::PrimeFillBuffers(void) - { - OMX_ERRORTYPE omx_err = OMX_ErrorNone; -- OpenMaxVideoBuffer *buffer; -+ COpenMaxVideoBuffer *buffer; - - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); -+ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - #endif - // tell OpenMax to start filling output buffers - for (size_t i = 0; i < m_omx_output_buffers.size(); i++) - { - buffer = m_omx_output_buffers[i]; - // always set the port index. -- buffer->omx_buffer->nOutputPortIndex = m_omx_output_port; -- // Need to clear the EOS flag. -- buffer->omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; -+ buffer->omx_buffer->nOutputPortIndex = m_omx_egl_render.GetOutputPort(); - buffer->omx_buffer->pAppPrivate = buffer; -- -- omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer); -- if (omx_err) -- CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -+ omx_err = ReturnOpenMaxBuffer(buffer); - } -- - return omx_err; - } - --OMX_ERRORTYPE COpenMaxVideo::AllocOMXInputBuffers(void) --{ -- OMX_ERRORTYPE omx_err = OMX_ErrorNone; -- -- // Obtain the information about the decoder input port. -- OMX_PARAM_PORTDEFINITIONTYPE port_format; -- OMX_INIT_STRUCTURE(port_format); -- port_format.nPortIndex = m_omx_input_port; -- OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format); -- -- #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, -- "%s::%s - iport(%d), nBufferCountMin(%lu), nBufferSize(%lu)\n", -- CLASSNAME, __func__, m_omx_input_port, port_format.nBufferCountMin, port_format.nBufferSize); -- #endif -- for (size_t i = 0; i < port_format.nBufferCountMin; i++) -- { -- OMX_BUFFERHEADERTYPE *buffer = NULL; -- // use an external buffer that's sized according to actual demux -- // packet size, start at internal's buffer size, will get deleted when -- // we start pulling demuxer packets and using demux packet sized buffers. -- OMX_U8* data = new OMX_U8[port_format.nBufferSize]; -- omx_err = OMX_UseBuffer(m_omx_decoder, &buffer, m_omx_input_port, NULL, port_format.nBufferSize, data); -- if (omx_err) -- { -- CLog::Log(LOGERROR, "%s::%s - OMX_UseBuffer failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -- return(omx_err); -- } -- m_omx_input_buffers.push_back(buffer); -- // don't have to lock/unlock here, we are not decoding -- m_omx_input_avaliable.push(buffer); -- } -- m_omx_input_eos = false; -- -- return(omx_err); --} --OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(bool wait) -+OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(void) - { - OMX_ERRORTYPE omx_err = OMX_ErrorNone; - -- /* -- omx_err = OMX_SendCommand(m_omx_decoder, OMX_CommandFlush, m_omx_input_port, 0); -- if (omx_err) -- CLog::Log(LOGERROR, "%s::%s - OMX_CommandFlush failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -- else if (wait) -- sem_wait(m_omx_flush_input); -- */ -- -- // free omx input port buffers. -- for (size_t i = 0; i < m_omx_input_buffers.size(); i++) -- { -- // using external buffers (OMX_UseBuffer), free our external buffers -- // before calling OMX_FreeBuffer which frees the omx buffer. -- delete [] m_omx_input_buffers[i]->pBuffer; -- m_omx_input_buffers[i]->pBuffer = NULL; -- omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_input_port, m_omx_input_buffers[i]); -- } -- m_omx_input_buffers.clear(); -- - // empty input buffer queue. not decoding so don't need lock/unlock. -- while (!m_omx_input_avaliable.empty()) -- m_omx_input_avaliable.pop(); - while (!m_demux_queue.empty()) - m_demux_queue.pop(); -+#ifdef DTS_QUEUE - while (!m_dts_queue.empty()) - m_dts_queue.pop(); -- -+#endif - return(omx_err); - } - --void COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata) -+bool COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata) - { - COpenMaxVideo *omx = static_cast(userdata); -- omx->AllocOMXOutputEGLTextures(); -+ return omx->AllocOMXOutputEGLTextures() == OMX_ErrorNone; - } - --void COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata) -+bool COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata) - { - COpenMaxVideo *omx = static_cast(userdata); -- omx->FreeOMXOutputEGLTextures(true); -+ return omx->FreeOMXOutputEGLTextures() == OMX_ErrorNone; - } - --OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputBuffers(void) -+bool COpenMaxVideo::AllocOMXOutputBuffers(void) - { -- OMX_ERRORTYPE omx_err; -- -- if ( g_application.IsCurrentThread() ) -- { -- omx_err = AllocOMXOutputEGLTextures(); -- } -- else -- { -- ThreadMessageCallback callbackData; -- callbackData.callback = &CallbackAllocOMXEGLTextures; -- callbackData.userptr = (void *)this; -- -- ThreadMessage tMsg; -- tMsg.dwMessage = TMSG_CALLBACK; -- tMsg.lpVoid = (void*)&callbackData; -- -- g_application.getApplicationMessenger().SendMessage(tMsg, true); -- -- omx_err = OMX_ErrorNone; -- } -- -- return omx_err; -+ return g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this); - } - --OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputBuffers(bool wait) -+bool COpenMaxVideo::FreeOMXOutputBuffers(void) - { -- OMX_ERRORTYPE omx_err = FreeOMXOutputEGLTextures(wait); -- -- return omx_err; -+ return g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this); - } - - OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - { -- OMX_ERRORTYPE omx_err; -- -- if (!eglCreateImageKHR) -- { -- GETEXTENSION(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR); -- } -- -+ OMX_ERRORTYPE omx_err = OMX_ErrorNone; - EGLint attrib = EGL_NONE; -- OpenMaxVideoBuffer *egl_buffer; -- -- // Obtain the information about the output port. -- OMX_PARAM_PORTDEFINITIONTYPE port_format; -- OMX_INIT_STRUCTURE(port_format); -- port_format.nPortIndex = m_omx_output_port; -- omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format); -- -- #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, -- "%s::%s (1) - oport(%d), nFrameWidth(%lu), nFrameHeight(%lu), nStride(%lx), nBufferCountMin(%lu), nBufferSize(%lu)\n", -- CLASSNAME, __func__, m_omx_output_port, -- port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride, -- port_format.nBufferCountMin, port_format.nBufferSize); -- #endif -+ COpenMaxVideoBuffer *egl_buffer; - - glActiveTexture(GL_TEXTURE0); - -- for (size_t i = 0; i < port_format.nBufferCountMin; i++) -+ for (size_t i = 0; i < m_egl_buffer_count; i++) - { -- egl_buffer = new OpenMaxVideoBuffer; -- memset(egl_buffer, 0, sizeof(*egl_buffer)); -+ egl_buffer = new COpenMaxVideoBuffer(this); - egl_buffer->width = m_decoded_width; - egl_buffer->height = m_decoded_height; - - glGenTextures(1, &egl_buffer->texture_id); - glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id); - -+ // no mipmaps -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -+ - // create space for buffer with a texture - glTexImage2D( - GL_TEXTURE_2D, // target -@@ -710,8 +928,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - GL_RGBA, // format - GL_UNSIGNED_BYTE, // type - NULL); // pixels -- will be provided later -- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // create EGLImage from texture - egl_buffer->egl_image = eglCreateImageKHR( -@@ -722,49 +938,40 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - &attrib); - if (!egl_buffer->egl_image) - { -- CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage\n", CLASSNAME, __func__); -+ CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage", CLASSNAME, __func__); - return(OMX_ErrorUndefined); - } - egl_buffer->index = i; - - // tell decoder output port that it will be using EGLImage -- omx_err = OMX_UseEGLImage( -- m_omx_decoder, &egl_buffer->omx_buffer, m_omx_output_port, egl_buffer, egl_buffer->egl_image); -+ omx_err = m_omx_egl_render.UseEGLImage( -+ &egl_buffer->omx_buffer, m_omx_egl_render.GetOutputPort(), egl_buffer, egl_buffer->egl_image); - if (omx_err) - { -- CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)\n", -+ CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)", - CLASSNAME, __func__, omx_err); - return(omx_err); - } - m_omx_output_buffers.push_back(egl_buffer); - -- CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d\n", -+ CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d", - CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height); - } -- m_omx_output_eos = false; -- while (!m_omx_output_busy.empty()) -- m_omx_output_busy.pop(); -- while (!m_omx_output_ready.empty()) -- m_omx_output_ready.pop(); -- - return omx_err; - } - --OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait) -+OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(void) - { - OMX_ERRORTYPE omx_err = OMX_ErrorNone; -- OpenMaxVideoBuffer *egl_buffer; -- -- if (!eglDestroyImageKHR) -- { -- GETEXTENSION(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR); -- } -+ COpenMaxVideoBuffer *egl_buffer; - - for (size_t i = 0; i < m_omx_output_buffers.size(); i++) - { - egl_buffer = m_omx_output_buffers[i]; - // tell decoder output port to stop using the EGLImage -- omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_output_port, egl_buffer->omx_buffer); -+ omx_err = m_omx_egl_render.FreeOutputBuffer(egl_buffer->omx_buffer); ++ omx_err = m_omx_mixer.FillThisBuffer(m_encoded_buffer); + if (omx_err != OMX_ErrorNone) -+ CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.FreeOutputBuffer(%p) omx_err(0x%08x)", CLASSNAME, __func__, egl_buffer->omx_buffer, omx_err); - // destroy egl_image - eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image); - // free texture -@@ -777,274 +984,45 @@ OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait) - } - - --//////////////////////////////////////////////////////////////////////////////////////////// --// DecoderEventHandler -- OMX event callback --OMX_ERRORTYPE COpenMaxVideo::DecoderEventHandler( -- OMX_HANDLETYPE hComponent, -- OMX_PTR pAppData, -- OMX_EVENTTYPE eEvent, -- OMX_U32 nData1, -- OMX_U32 nData2, -- OMX_PTR pEventData) --{ -- OMX_ERRORTYPE omx_err; -- COpenMaxVideo *ctx = static_cast(pAppData); -- --/* -- #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, -- "COpenMax::%s - hComponent(0x%p), eEvent(0x%x), nData1(0x%lx), nData2(0x%lx), pEventData(0x%p)\n", -- __func__, hComponent, eEvent, nData1, nData2, pEventData); -- #endif --*/ -- -- switch (eEvent) -- { -- case OMX_EventCmdComplete: -- switch(nData1) -- { -- case OMX_CommandStateSet: -- ctx->m_omx_decoder_state = (int)nData2; -- switch (ctx->m_omx_decoder_state) -- { -- case OMX_StateInvalid: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateInvalid\n", CLASSNAME, __func__); -- break; -- case OMX_StateLoaded: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateLoaded\n", CLASSNAME, __func__); -- break; -- case OMX_StateIdle: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateIdle\n", CLASSNAME, __func__); -- break; -- case OMX_StateExecuting: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateExecuting\n", CLASSNAME, __func__); -- break; -- case OMX_StatePause: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_StatePause\n", CLASSNAME, __func__); -- break; -- case OMX_StateWaitForResources: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateWaitForResources\n", CLASSNAME, __func__); -- break; -- default: -- CLog::Log(LOGDEBUG, -- "%s::%s - Unknown OMX_Statexxxxx, state(%d)\n", -- CLASSNAME, __func__, ctx->m_omx_decoder_state); -- break; -- } -- sem_post(ctx->m_omx_decoder_state_change); -- break; -- case OMX_CommandFlush: -- /* -- if (OMX_ALL == (int)nData2) -- { -- sem_post(ctx->m_omx_flush_input); -- sem_post(ctx->m_omx_flush_output); -- CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input/output\n",__func__); -- } -- else if (ctx->m_omx_input_port == (int)nData2) -- { -- sem_post(ctx->m_omx_flush_input); -- CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input\n",__func__); -- } -- else if (ctx->m_omx_output_port == (int)nData2) -- { -- sem_post(ctx->m_omx_flush_output); -- CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush ouput\n",__func__); -- } -- else -- */ -- { -- #if defined(OMX_DEBUG_EVENTHANDLER) -- CLog::Log(LOGDEBUG, -- "%s::%s - OMX_CommandFlush, nData2(0x%lx)\n", -- CLASSNAME, __func__, nData2); -- #endif -- } -- break; -- case OMX_CommandPortDisable: -- #if defined(OMX_DEBUG_EVENTHANDLER) -- CLog::Log(LOGDEBUG, -- "%s::%s - OMX_CommandPortDisable, nData1(0x%lx), nData2(0x%lx)\n", -- CLASSNAME, __func__, nData1, nData2); -- #endif -- if (ctx->m_omx_output_port == (int)nData2) -- { -- // Got OMX_CommandPortDisable event, alloc new buffers for the output port. -- ctx->AllocOMXOutputBuffers(); -- omx_err = OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortEnable, ctx->m_omx_output_port, NULL); -- } -- break; -- case OMX_CommandPortEnable: -- #if defined(OMX_DEBUG_EVENTHANDLER) -- CLog::Log(LOGDEBUG, -- "%s::%s - OMX_CommandPortEnable, nData1(0x%lx), nData2(0x%lx)\n", -- CLASSNAME, __func__, nData1, nData2); -- #endif -- if (ctx->m_omx_output_port == (int)nData2) -- { -- // Got OMX_CommandPortEnable event. -- // OMX_CommandPortDisable will have re-alloced new ones so re-prime -- ctx->PrimeFillBuffers(); -- } -- ctx->m_portChanging = false; -- break; -- #if defined(OMX_DEBUG_EVENTHANDLER) -- case OMX_CommandMarkBuffer: -- CLog::Log(LOGDEBUG, -- "%s::%s - OMX_CommandMarkBuffer, nData1(0x%lx), nData2(0x%lx)\n", -- CLASSNAME, __func__, nData1, nData2); -- break; -- #endif -- } -- break; -- case OMX_EventBufferFlag: -- if (ctx->m_omx_decoder == hComponent && (nData2 & OMX_BUFFERFLAG_EOS)) { -- #if defined(OMX_DEBUG_EVENTHANDLER) -- if(ctx->m_omx_input_port == (int)nData1) -- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(input)\n", -- CLASSNAME, __func__); -- #endif -- if(ctx->m_omx_output_port == (int)nData1) -- { -- ctx->m_videoplayback_done = true; -- #if defined(OMX_DEBUG_EVENTHANDLER) -- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(output)\n", -- CLASSNAME, __func__); -- #endif -- } -- } -- break; -- case OMX_EventPortSettingsChanged: -- #if defined(OMX_DEBUG_EVENTHANDLER) -- CLog::Log(LOGDEBUG, -- "%s::%s - OMX_EventPortSettingsChanged(output)\n", CLASSNAME, __func__); -- #endif -- // not sure nData2 is the input/output ports in this call, docs don't say -- if (ctx->m_omx_output_port == (int)nData2) -- { -- // free the current OpenMax output buffers, you must do this before sending -- // OMX_CommandPortDisable to component as it expects output buffers -- // to be freed before it will issue a OMX_CommandPortDisable event. -- ctx->m_portChanging = true; -- OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortDisable, ctx->m_omx_output_port, NULL); -- omx_err = ctx->FreeOMXOutputBuffers(false); -- } -- break; -- #if defined(OMX_DEBUG_EVENTHANDLER) -- case OMX_EventMark: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventMark\n", CLASSNAME, __func__); -- break; -- case OMX_EventResourcesAcquired: -- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventResourcesAcquired\n", CLASSNAME, __func__); -- break; -- #endif -- case OMX_EventError: -- switch((OMX_S32)nData1) -- { -- case OMX_ErrorInsufficientResources: -- CLog::Log(LOGERROR, "%s::%s - OMX_EventError, insufficient resources\n", -- CLASSNAME, __func__); -- // we are so frack'ed -- //exit(0); -- break; -- case OMX_ErrorFormatNotDetected: -- CLog::Log(LOGERROR, "%s::%s - OMX_EventError, cannot parse input stream\n", -- CLASSNAME, __func__); -- break; -- case OMX_ErrorPortUnpopulated: -- // silently ignore these. We can get them when setting OMX_CommandPortDisable -- // on the output port and the component flushes the output buffers. -- break; -- case OMX_ErrorStreamCorrupt: -- CLog::Log(LOGERROR, "%s::%s - OMX_EventError, Bitstream corrupt\n", -- CLASSNAME, __func__); -- ctx->m_videoplayback_done = true; -- break; -- default: -- CLog::Log(LOGERROR, "%s::%s - OMX_EventError detected, nData1(0x%lx), nData2(0x%lx)\n", -- CLASSNAME, __func__, nData1, nData2); -- break; -- } -- // do this so we don't hang on errors -- /* -- sem_post(ctx->m_omx_flush_input); -- sem_post(ctx->m_omx_flush_output); -- */ -- sem_post(ctx->m_omx_decoder_state_change); -- break; -- default: -- CLog::Log(LOGWARNING, -- "%s::%s - Unknown eEvent(0x%x), nData1(0x%lx), nData2(0x%lx)\n", -- CLASSNAME, __func__, eEvent, nData1, nData2); -- break; -- } -- -- return OMX_ErrorNone; --} -- --// StartPlayback -- Kick off video playback. --OMX_ERRORTYPE COpenMaxVideo::StartDecoder(void) --{ -- OMX_ERRORTYPE omx_err; -- -- #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); -- #endif -- -- // transition decoder component to IDLE state -- omx_err = SetStateForComponent(OMX_StateIdle); -- if (omx_err) -- { -- CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -- return omx_err; -- } -- -- // transition decoder component to executing state -- omx_err = SetStateForComponent(OMX_StateExecuting); -- if (omx_err) -- { -- CLog::Log(LOGERROR, "%s::%s - setting OMX_StateExecuting failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -- return omx_err; -- } -- -- //prime the omx output buffers. -- PrimeFillBuffers(); -- -- return omx_err; --} -- - // StopPlayback -- Stop video playback - OMX_ERRORTYPE COpenMaxVideo::StopDecoder(void) - { -- OMX_ERRORTYPE omx_err; -+ OMX_ERRORTYPE omx_err = OMX_ErrorNone; - - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); -+ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - #endif ++ return false; + - // transition decoder component from executing to idle -- omx_err = SetStateForComponent(OMX_StateIdle); -- if (omx_err) -+ if (m_omx_decoder.IsInitialized()) - { -- CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -- return omx_err; -+ omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle); -+ if (omx_err) -+ CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)", -+ CLASSNAME, __func__, omx_err); - } - - // we can free our allocated port buffers in OMX_StateIdle state. - // free OpenMax input buffers. -- FreeOMXInputBuffers(true); -- // free OpenMax output buffers. -- FreeOMXOutputBuffers(true); -+ FreeOMXInputBuffers(); ++ omx_err = m_omx_mixer.WaitForOutputDone(1000); ++ if (omx_err != OMX_ErrorNone) ++ { ++ CLog::Log(LOGERROR, "%s::%s m_omx_mixer.WaitForOutputDone result(0x%x)", CLASSNAME, __func__, omx_err); ++ return false; ++ } ++ assert(m_encoded_buffer->nFilledLen > 0 && m_encoded_buffer->nFilledLen <= m_encoded_buffer->nAllocLen); + -+ if (m_omx_egl_render.IsInitialized()) -+ { -+ omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateIdle); -+ if (omx_err) -+ CLog::Log(LOGERROR, "%s::%s - setting egl OMX_StateIdle failed with omx_err(0x%x)", -+ CLASSNAME, __func__, omx_err); -+ // free OpenMax output buffers. -+ omx_err = m_omx_egl_render.DisablePort(m_omx_egl_render.GetOutputPort(), false); -+ if (omx_err != OMX_ErrorNone) -+ CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.DisablePort(%d) omx_err(0x%08x)", CLASSNAME, __func__, m_omx_egl_render.GetOutputPort(), omx_err); - -- // transition decoder component from idle to loaded -- omx_err = SetStateForComponent(OMX_StateLoaded); -- if (omx_err) -- CLog::Log(LOGERROR, -- "%s::%s - setting OMX_StateLoaded failed with omx_err(0x%x)\n", -- CLASSNAME, __func__, omx_err); -+ FreeOMXOutputBuffers(); - -+ omx_err = m_omx_egl_render.WaitForCommand(OMX_CommandPortDisable, m_omx_egl_render.GetOutputPort()); -+ if (omx_err != OMX_ErrorNone) -+ CLog::Log(LOGERROR, "%s::%s WaitForCommand:OMX_CommandPortDisable omx_err(0x%08x)", CLASSNAME, __func__, omx_err); ++ if (m_omx_mixer.BadState()) ++ { ++ CLog::Log(LOGERROR, "%s::%s m_omx_mixer.BadState", CLASSNAME, __func__); ++ return false; ++ } ++ ++ if (m_encoded_buffer->nFilledLen) ++ { ++ int samples_available = m_encoded_buffer->nFilledLen / d_samplesize; ++ int samples = std::min(samples_available, dst_samples - received); ++ copy_planes(dst_buffer, d_pitch, d_planes, d_samplesize, received, (uint8_t *)m_encoded_buffer->pBuffer, samples); ++ received += samples; ++ samples_available -= samples; ++ if (samples_available > 0) ++ m_encoded_buffer->nOffset += samples; ++ else ++ m_encoded_buffer = NULL; ++ } + } - return omx_err; - } - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -index e06c41d..9079c13 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -@@ -21,12 +21,35 @@ - - #if defined(HAVE_LIBOPENMAX) - --#include "OpenMax.h" -+#include "system_gl.h" - #include - #include - ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s format:%d->%d rate:%d->%d chan:%d->%d samples %d->%d (%f) %d =%d", CLASSNAME, __func__, ++ (int)m_src_fmt, (int)m_dst_fmt, m_src_rate, m_dst_rate, m_src_channels, m_dst_channels, src_samples, dst_samples, ratio, m_Initialized, received); ++ #endif ++ assert(received <= dst_samples); ++ return received; ++} ++ ++int64_t CActiveAEResample::GetDelay(int64_t base) ++{ ++ int ret = m_dst_rate ? 1000 * GetBufferedSamples() / m_dst_rate : 0; ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); ++ #endif ++ return ret; ++} ++ ++int CActiveAEResample::GetBufferedSamples() ++{ ++ int samples = 0; ++ if (m_encoded_buffer) ++ { ++ const int d_samplesize = m_dst_channels * m_dst_bits >> 3; ++ samples = m_encoded_buffer->nFilledLen / d_samplesize - m_encoded_buffer->nOffset; ++ } ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, samples); ++ #endif ++ return samples; ++} ++ ++int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate) ++{ ++ int ret = ((long long)src_samples * dst_rate + src_rate-1) / src_rate; ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); ++ #endif ++ return ret; ++} ++ ++int CActiveAEResample::GetSrcBufferSize(int samples) ++{ ++ int ret = 0; ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); ++ #endif ++ return ret; ++} ++ ++int CActiveAEResample::GetDstBufferSize(int samples) ++{ ++ int ret = CalcDstSampleCount(samples, m_dst_rate, m_src_rate); ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); ++ #endif ++ return ret; ++} ++ ++uint64_t CActiveAEResample::GetAVChannelLayout(CAEChannelInfo &info) ++{ ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ #endif ++ uint64_t channelLayout = 0; ++ if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT; ++ if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT; ++ if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER; ++ if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY; ++ if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT; ++ if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT; ++ if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER; ++ if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER; ++ if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER; ++ if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT; ++ if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT; ++ if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER; ++ if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT; ++ if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER; ++ if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT; ++ if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT; ++ if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER; ++ if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT; ++ ++ return channelLayout; ++} ++ ++AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) ++{ ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ #endif ++ if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8; ++ else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; ++ else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; ++ else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; ++ ++ else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P; ++ else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; ++ else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; ++ else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P; ++ else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; ++ else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; ++ ++ if (AE_IS_PLANAR(format)) ++ return AV_SAMPLE_FMT_FLTP; ++ else ++ return AV_SAMPLE_FMT_FLT; ++} ++ ++uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel) ++{ ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ #endif ++ switch (aechannel) ++ { ++ case AE_CH_FL: return AV_CH_FRONT_LEFT; ++ case AE_CH_FR: return AV_CH_FRONT_RIGHT; ++ case AE_CH_FC: return AV_CH_FRONT_CENTER; ++ case AE_CH_LFE: return AV_CH_LOW_FREQUENCY; ++ case AE_CH_BL: return AV_CH_BACK_LEFT; ++ case AE_CH_BR: return AV_CH_BACK_RIGHT; ++ case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER; ++ case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER; ++ case AE_CH_BC: return AV_CH_BACK_CENTER; ++ case AE_CH_SL: return AV_CH_SIDE_LEFT; ++ case AE_CH_SR: return AV_CH_SIDE_RIGHT; ++ case AE_CH_TC: return AV_CH_TOP_CENTER; ++ case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT; ++ case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER; ++ case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT; ++ case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT; ++ case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER; ++ case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT; ++ default: ++ return 0; ++ } ++} ++ ++int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) ++{ ++ #ifdef DEBUG_VERBOSE ++ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ #endif ++ return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); ++} ++ ++#endif +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h +new file mode 100644 +index 0000000..b88a90b +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h +@@ -0,0 +1,63 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ +#include "linux/OMXCore.h" -+#include "linux/OMXClock.h" + -+#include "cores/dvdplayer/DVDStreamInfo.h" -+#include "DVDVideoCodec.h" -+#include "threads/Event.h" ++namespace ActiveAE ++{ + -+#include -+#include -+ -+typedef struct omx_demux_packet { -+ OMX_U8 *buff; -+ int size; -+ double dts; -+ double pts; -+} omx_demux_packet; -+ -+class COpenMaxVideo; - // an omx egl video frame --typedef struct OpenMaxVideoBuffer { -+class COpenMaxVideoBuffer ++class CActiveAEResample +{ +public: -+ COpenMaxVideoBuffer(COpenMaxVideo *omv); -+ virtual ~COpenMaxVideoBuffer(); ++ CActiveAEResample(); ++ virtual ~CActiveAEResample(); ++ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality); ++ int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio); ++ int64_t GetDelay(int64_t base); ++ int GetBufferedSamples(); ++ int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate); ++ int GetSrcBufferSize(int samples); ++ int GetDstBufferSize(int samples); ++ static uint64_t GetAVChannelLayout(CAEChannelInfo &info); ++// static CAEChannelInfo GetAEChannelLayout(uint64_t layout); ++ static AVSampleFormat GetAVSampleFormat(AEDataFormat format); ++ static AEDataFormat GetAESampleFormat(AVSampleFormat format, int bits); ++ static uint64_t GetAVChannel(enum AEChannel aechannel); ++ int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); + - OMX_BUFFERHEADERTYPE *omx_buffer; - int width; - int height; -@@ -35,79 +58,86 @@ typedef struct OpenMaxVideoBuffer { - // used for egl based rendering if active - EGLImageKHR egl_image; - GLuint texture_id; --} OpenMaxVideoBuffer; -+ // reference counting -+ COpenMaxVideoBuffer* Acquire(); -+ long Release(); -+ void Sync(); ++protected: ++ void DeInit(); ++ uint64_t m_src_chan_layout, m_dst_chan_layout; ++ int m_src_rate, m_dst_rate; ++ int m_src_channels, m_dst_channels; ++ AVSampleFormat m_src_fmt, m_dst_fmt; ++ int m_src_bits, m_dst_bits; + -+ COpenMaxVideo *m_omv; -+ long m_refs; -+private: ++ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input; ++ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output; ++ COMXCoreComponent m_omx_mixer; ++ bool m_Initialized; ++ AVSampleFormat m_last_src_fmt, m_last_dst_fmt; ++ int m_last_src_channels, m_last_dst_channels; ++ OMX_BUFFERHEADERTYPE *m_encoded_buffer; +}; ++ ++} +diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in +index 581249e..20c05bb 100644 +--- a/xbmc/cores/AudioEngine/Makefile.in ++++ b/xbmc/cores/AudioEngine/Makefile.in +@@ -31,6 +31,7 @@ SRCS += Engines/ActiveAE/ActiveAESink.cpp + SRCS += Engines/ActiveAE/ActiveAEStream.cpp + SRCS += Engines/ActiveAE/ActiveAESound.cpp + SRCS += Engines/ActiveAE/ActiveAEResample.cpp ++SRCS += Engines/ActiveAE/ActiveAEResamplePi.cpp + SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp --class COpenMaxVideo : public COpenMax -+class COpenMaxVideo + ifeq (@USE_ANDROID@,1) +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp +index 7af2078..b199acd 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp +@@ -78,9 +78,9 @@ static void SetAudioProps(bool stream_channels, uint32_t channel_map) + CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map); + } + +-static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough) ++static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough) { - public: - COpenMaxVideo(); - virtual ~COpenMaxVideo(); +- unsigned int channels = format.m_channelLayout.Count(); ++ unsigned int channels = channelLayout.Count(); + uint32_t channel_map = 0; + if (passthrough) + return 0; +@@ -119,12 +119,12 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough) + // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels + // but no BR BL channels, we use the wide map in order to open only the num of channels really + // needed. +- if (format.m_channelLayout.HasChannel(AE_CH_BL) && !format.m_channelLayout.HasChannel(AE_CH_SL)) ++ if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL)) + map = map_back; - // Required overrides -- bool Open(CDVDStreamInfo &hints); -- void Close(void); -- int Decode(uint8_t *pData, int iSize, double dts, double pts); -- void Reset(void); -- bool GetPicture(DVDVideoPicture *pDvdVideoPicture); -- void SetDropState(bool bDrop); -+ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); -+ virtual void Dispose(void); -+ virtual int Decode(uint8_t *pData, int iSize, double dts, double pts); -+ virtual void Reset(void); -+ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture); -+ virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); -+ virtual unsigned GetAllowedReferences() { return 2; } -+ virtual void SetDropState(bool bDrop); -+ virtual const char* GetName(void) { return (const char*)m_pFormatName; } -+ -+ // OpenMax decoder callback routines. -+ OMX_ERRORTYPE DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer); -+ void ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer); -+ - protected: - void QueryCodec(void); - OMX_ERRORTYPE PrimeFillBuffers(void); - OMX_ERRORTYPE AllocOMXInputBuffers(void); -- OMX_ERRORTYPE FreeOMXInputBuffers(bool wait); -- OMX_ERRORTYPE AllocOMXOutputBuffers(void); -- OMX_ERRORTYPE FreeOMXOutputBuffers(bool wait); -- static void CallbackAllocOMXEGLTextures(void*); -+ OMX_ERRORTYPE FreeOMXInputBuffers(void); -+ bool AllocOMXOutputBuffers(void); -+ bool FreeOMXOutputBuffers(void); -+ static bool CallbackAllocOMXEGLTextures(void*); - OMX_ERRORTYPE AllocOMXOutputEGLTextures(void); -- static void CallbackFreeOMXEGLTextures(void*); -- OMX_ERRORTYPE FreeOMXOutputEGLTextures(bool wait); -- -- // TODO Those should move into the base class. After start actions can be executed by callbacks. -- OMX_ERRORTYPE StartDecoder(void); -+ static bool CallbackFreeOMXEGLTextures(void*); -+ OMX_ERRORTYPE FreeOMXOutputEGLTextures(void); - OMX_ERRORTYPE StopDecoder(void); -- -- // OpenMax decoder callback routines. -- virtual OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, -- OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData); -- virtual OMX_ERRORTYPE DecoderEmptyBufferDone( -- OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer); -- virtual OMX_ERRORTYPE DecoderFillBufferDone( -- OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader); -+ OMX_ERRORTYPE ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer); - - // EGL Resources - EGLDisplay m_egl_display; - EGLContext m_egl_context; - - // Video format -- DVDVideoPicture m_videobuffer; - bool m_drop_state; - int m_decoded_width; - int m_decoded_height; -+ unsigned int m_egl_buffer_count; -+ -+ bool m_port_settings_changed; -+ const char *m_pFormatName; - - std::queue m_dts_queue; - std::queue m_demux_queue; - -- // OpenMax input buffers (demuxer packets) -- pthread_mutex_t m_omx_input_mutex; -- std::queue m_omx_input_avaliable; -- std::vector m_omx_input_buffers; -- bool m_omx_input_eos; -- int m_omx_input_port; -- //sem_t *m_omx_flush_input; -- CEvent m_input_consumed_event; -- - // OpenMax output buffers (video frames) - pthread_mutex_t m_omx_output_mutex; -- std::queue m_omx_output_busy; -- std::queue m_omx_output_ready; -- std::vector m_omx_output_buffers; -- bool m_omx_output_eos; -- int m_omx_output_port; -- //sem_t *m_omx_flush_output; -+ std::vector m_omx_output_busy; -+ std::queue m_omx_output_ready; -+ std::vector m_omx_output_buffers; -+ -+ // initialize OpenMax and get decoder component -+ bool Initialize( const CStdString &decoder_name); -+ -+ // Components -+ COMXCoreComponent m_omx_decoder; -+ COMXCoreComponent m_omx_egl_render; - -- bool m_portChanging; -+ COMXCoreTunel m_omx_tunnel; -+ OMX_VIDEO_CODINGTYPE m_codingType; - -- volatile bool m_videoplayback_done; -+ bool PortSettingsChanged(); -+ bool SendDecoderConfig(uint8_t *extradata, int extrasize); -+ bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize); - }; - - // defined(HAVE_LIBOPENMAX) -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 8de1e96..87a1a9f 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -2968,7 +2968,9 @@ bool CDVDPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) - hint.aspect = aspect; - hint.forced_aspect = true; - } -+#ifndef TARGET_RASPBERRY_PI - hint.software = true; -+#endif - } - - CDVDInputStream::IMenus* pMenus = dynamic_cast(m_pInputStream); -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -index ac78f18..5fdd63b 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp -@@ -324,6 +324,9 @@ void CDVDPlayerVideo::Process() - - while (!m_bStop) + for (unsigned int i = 0; i < channels; ++i) { -+ DemuxPacket staticPacket = {}; -+ DemuxPacket* pPacket = NULL; -+ bool bPacketDrop = false; - int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000; - int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0; +- AEChannel c = format.m_channelLayout[i]; ++ AEChannel c = channelLayout[i]; + unsigned int chan = 0; + if ((unsigned int)c < sizeof map_normal / sizeof *map_normal) + chan = map[(unsigned int)c]; +@@ -155,9 +155,9 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough) + 0xff, // 7 + 0x13, // 7.1 + }; +- uint8_t cea = format.m_channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels]; ++ uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels]; + if (cea == 0xff) +- CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, format.m_channelLayout.HasChannel(AE_CH_LFE), channels); ++ CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels); -@@ -360,8 +363,10 @@ void CDVDPlayerVideo::Process() - OutputPicture(&picture, pts); - pts+= frametime; - } -- -- continue; -+ pPacket = &staticPacket; -+ bPacketDrop = false; -+ goto submit_empty_packet; -+ //continue; - } + channel_map |= cea << 24; - if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE)) -@@ -490,9 +495,12 @@ void CDVDPlayerVideo::Process() +@@ -191,7 +191,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device) + format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER / NUM_OMX_BUFFERS; + format.m_frameSamples = format.m_frames * channels; - if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) - { -- DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); -- bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); -- -+ pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); -+ bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); -+ } -+submit_empty_packet: -+ if (ret == MSGQ_TIMEOUT || pMsg->IsType(CDVDMsg::DEMUXER_PACKET)) -+ { - if (m_stalled) - { - CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe left, switching to normal playback"); -@@ -750,7 +758,8 @@ void CDVDPlayerVideo::Process() - } +- SetAudioProps(m_passthrough, GetChannelMap(format, m_passthrough)); ++ SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough)); - // all data is used by the decoder, we can safely free it now -- pMsg->Release(); -+ if (ret != MSGQ_TIMEOUT) -+ pMsg->Release(); - } - - // we need to let decoder release any picture retained resources. + m_format = format; + m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate); diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp -index 4ae29ba..6cc4970 100644 +index 4ae29ba..4caa304 100644 --- a/xbmc/linux/OMXCore.cpp +++ b/xbmc/linux/OMXCore.cpp -@@ -431,7 +431,12 @@ void COMXCoreComponent::FlushInput() - CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - Error on component %s omx_err(0x%08x)", - m_componentName.c_str(), (int)omx_err); - } -- WaitForCommand(OMX_CommandFlush, m_input_port); -+ omx_err = WaitForCommand(OMX_CommandFlush, m_input_port); -+ if(omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - %s WaitForCommand omx_err(0x%08x)", -+ m_componentName.c_str(), (int)omx_err); -+ } - } +@@ -419,7 +419,7 @@ void COMXCoreComponent::FlushAll() + + void COMXCoreComponent::FlushInput() + { +- if(!m_handle) ++ if(!m_handle || m_resource_error) + return; + + OMX_ERRORTYPE omx_err = OMX_ErrorNone; +@@ -436,7 +436,7 @@ void COMXCoreComponent::FlushInput() void COMXCoreComponent::FlushOutput() -@@ -448,7 +453,12 @@ void COMXCoreComponent::FlushOutput() - CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - Error on component %s omx_err(0x%08x)", - m_componentName.c_str(), (int)omx_err); - } -- WaitForCommand(OMX_CommandFlush, m_output_port); -+ omx_err = WaitForCommand(OMX_CommandFlush, m_output_port); -+ if(omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - %s WaitForCommand omx_err(0x%08x)", -+ m_componentName.c_str(), (int)omx_err); -+ } - } - - // timeout in milliseconds -@@ -1120,7 +1130,12 @@ OMX_STATETYPE COMXCoreComponent::GetState() const - - OMX_STATETYPE state; - -- OMX_GetState(m_handle, &state); -+ OMX_ERRORTYPE omx_err = OMX_GetState(m_handle, &state); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "COMXCoreComponent::GetState - %s failed with omx_err(0x%x)\n", -+ m_componentName.c_str(), omx_err); -+ } - return state; - } - -@@ -1278,6 +1293,8 @@ OMX_ERRORTYPE COMXCoreComponent::DisablePort(unsigned int port, bool wait) - - OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage) { -+if (m_callbacks.FillBufferDone == &COMXCoreComponent::DecoderFillBufferDoneCallback) -+{ - OMX_ERRORTYPE omx_err = OMX_ErrorNone; - - if(!m_handle) -@@ -1354,8 +1371,21 @@ OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, - - return omx_err; - } -+else -+{ -+ OMX_ERRORTYPE omx_err; -+ omx_err = OMX_UseEGLImage(m_handle, ppBufferHdr, nPortIndex, pAppPrivate, eglImage); -+ if(omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - %s failed with omx_err(0x%x)\n", -+ CLASSNAME, __func__, m_componentName.c_str(), omx_err); -+ return omx_err; -+ } -+ return omx_err; -+} -+} - --bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEXTYPE index) -+bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEXTYPE index, OMX_CALLBACKTYPE *callbacks) - { - OMX_ERRORTYPE omx_err; - -@@ -1390,6 +1420,13 @@ bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEX - m_callbacks.EmptyBufferDone = &COMXCoreComponent::DecoderEmptyBufferDoneCallback; - m_callbacks.FillBufferDone = &COMXCoreComponent::DecoderFillBufferDoneCallback; - -+ if (callbacks && callbacks->EventHandler) -+ m_callbacks.EventHandler = callbacks->EventHandler; -+ if (callbacks && callbacks->EmptyBufferDone) -+ m_callbacks.EmptyBufferDone = callbacks->EmptyBufferDone; -+ if (callbacks && callbacks->FillBufferDone) -+ m_callbacks.FillBufferDone = callbacks->FillBufferDone; -+ - // Get video component handle setting up callbacks, component is in loaded state on return. - if(!m_handle) - { -diff --git a/xbmc/linux/OMXCore.h b/xbmc/linux/OMXCore.h -index 05052e5..6ade180 100644 ---- a/xbmc/linux/OMXCore.h -+++ b/xbmc/linux/OMXCore.h -@@ -107,7 +107,7 @@ class COMXCoreComponent - OMX_ERRORTYPE DisablePort(unsigned int port, bool wait = true); - OMX_ERRORTYPE UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage); - -- bool Initialize( const std::string &component_name, OMX_INDEXTYPE index); -+ bool Initialize( const std::string &component_name, OMX_INDEXTYPE index, OMX_CALLBACKTYPE *callbacks = NULL); - bool IsInitialized() const { return m_handle != NULL; } - bool Deinitialize(); - --- -2.0.4 - - -From 10d7a165dce2be2673dd973eb135d616dcbb71bc Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 20 Jan 2014 16:03:40 +0000 -Subject: [PATCH 20/98] [omxcodec] Enable for dvd menus - ---- - xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -index 34cc95d..e713967 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp -@@ -184,6 +184,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne - - CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str()); - -+#if defined(HAVE_LIBOPENMAX) -+ // libopenmax can handle dvd playback including stills -+ if (!CSettings::Get().GetBool("videoplayer.useomx")) -+#endif - if (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO)) - { - // If dvd is an mpeg2 and hint.stills --- -2.0.4 - - -From 6415c8052793080b20c83a9a1f885fe73d174cd2 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 3 Feb 2014 22:27:44 +0000 -Subject: [PATCH 21/98] [omxcodec] Add omx specific texture - create/upload/delete functions - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 33 +++++++++++++++++++++++++ - xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 4 +++ - 2 files changed, 37 insertions(+) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 2e0d0ca..b8af8d0 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -803,6 +803,12 @@ void CLinuxRendererGLES::LoadShaders(int field) - m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture; - m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture; - } -+ else if (m_format == RENDER_FMT_OMXEGL) -+ { -+ m_textureUpload = &CLinuxRendererGLES::UploadOMXEGLTexture; -+ m_textureCreate = &CLinuxRendererGLES::CreateOMXEGLTexture; -+ m_textureDelete = &CLinuxRendererGLES::DeleteOMXEGLTexture; -+ } - else - { - // default to YV12 texture handlers -@@ -2485,6 +2491,33 @@ bool CLinuxRendererGLES::CreateSurfaceTexture(int index) - return true; - } - -+//******************************************************************************************************** -+// SurfaceTexture creation, deletion, copying + clearing -+//******************************************************************************************************** -+void CLinuxRendererGLES::UploadOMXEGLTexture(int index) -+{ -+#ifdef HAVE_LIBOPENMAX -+ YUVBUFFER &buf = m_buffers[index]; -+ if (buf.openMaxBuffer) -+ { -+ //buf.openMaxBuffer->Sync(); -+ } -+#endif -+} -+void CLinuxRendererGLES::DeleteOMXEGLTexture(int index) -+{ -+#ifdef HAVE_LIBOPENMAX -+ YUVBUFFER &buf = m_buffers[index]; -+ if (buf.openMaxBuffer) -+ SAFE_RELEASE(buf.openMaxBuffer); -+#endif -+} -+bool CLinuxRendererGLES::CreateOMXEGLTexture(int index) -+{ -+ DeleteOMXEGLTexture(index); -+ return true; -+} -+ - void CLinuxRendererGLES::SetTextureFilter(GLenum method) - { - for (int i = 0 ; i -Date: Mon, 3 Feb 2014 22:50:43 +0000 -Subject: [PATCH 22/98] [omxcodec] Add shared pointer to delay shutdown of - codec until buffers are returned - ---- - .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 13 +++---------- - .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 3 ++- - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 21 ++++++++++++++++++++- - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 5 ++++- - 4 files changed, 29 insertions(+), 13 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -index 7d33192..ef10555 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -@@ -28,7 +28,6 @@ - #include "DVDClock.h" - #include "DVDStreamInfo.h" - #include "DVDVideoCodecOpenMax.h" --#include "OpenMaxVideo.h" - #include "settings/Settings.h" - #include "utils/log.h" - -@@ -36,8 +35,8 @@ - //////////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////////////////// - CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() -+ : m_omx_decoder( new COpenMaxVideo ) - { -- m_omx_decoder = NULL; - CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this); - } - -@@ -49,8 +48,7 @@ CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax() - - bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - { -- m_omx_decoder = new COpenMaxVideo; -- return m_omx_decoder->Open(hints, options); -+ return m_omx_decoder->Open(hints, options, m_omx_decoder); - } - - const char* CDVDVideoCodecOpenMax::GetName(void) -@@ -60,12 +58,7 @@ const char* CDVDVideoCodecOpenMax::GetName(void) - - void CDVDVideoCodecOpenMax::Dispose() - { -- if (m_omx_decoder) -- { -- m_omx_decoder->Dispose(); -- delete m_omx_decoder; -- m_omx_decoder = NULL; -- } -+ m_omx_decoder->Dispose(); - } - - void CDVDVideoCodecOpenMax::SetDropState(bool bDrop) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -index 67cc235..b7c0c1b 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -@@ -22,6 +22,7 @@ - #if defined(HAVE_LIBOPENMAX) - - #include "DVDVideoCodec.h" -+#include "OpenMaxVideo.h" - - class COpenMaxVideo; - class CDVDVideoCodecOpenMax : public CDVDVideoCodec -@@ -42,7 +43,7 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec - virtual const char* GetName(void); - - protected: -- COpenMaxVideo *m_omx_decoder; -+ OpenMaxVideoPtr m_omx_decoder; - }; - - #endif -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index aca2e0d..29b5bb9 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -126,6 +126,7 @@ COpenMaxVideo::COpenMaxVideo() - m_egl_buffer_count = 0; - - m_port_settings_changed = false; -+ m_finished = false; - m_pFormatName = "omx-xxxx"; - } - -@@ -134,6 +135,7 @@ COpenMaxVideo::~COpenMaxVideo() - #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); - #endif -+ assert(m_finished); - if (m_omx_decoder.IsInitialized()) - { - if (m_omx_tunnel.IsInitialized()) -@@ -149,7 +151,7 @@ COpenMaxVideo::~COpenMaxVideo() - pthread_mutex_destroy(&m_omx_output_mutex); - } - --bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) -+bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself) - { - #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); -@@ -161,6 +163,7 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) +- if(!m_handle) ++ if(!m_handle || m_resource_error) + return; OMX_ERRORTYPE omx_err = OMX_ErrorNone; - -+ m_myself = myself; - m_decoded_width = hints.width; - m_decoded_height = hints.height; - -@@ -331,6 +334,15 @@ void COpenMaxVideo::Dispose() - #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - #endif -+ // we are happy to exit, but let last shared pointer being deleted trigger the destructor -+ bool done = false; -+ pthread_mutex_lock(&m_omx_output_mutex); -+ if (m_omx_output_busy.empty()) -+ done = true; -+ m_finished = true; -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ if (done) -+ m_myself.reset(); - } - - void COpenMaxVideo::SetDropState(bool bDrop) -@@ -752,6 +764,13 @@ void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer) - m_omx_output_busy.erase(std::remove(m_omx_output_busy.begin(), m_omx_output_busy.end(), buffer), m_omx_output_busy.end()); - pthread_mutex_unlock(&m_omx_output_mutex); - ReturnOpenMaxBuffer(buffer); -+ bool done = false; -+ pthread_mutex_lock(&m_omx_output_mutex); -+ if (m_finished && m_omx_output_busy.empty()) -+ done = true; -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ if (done) -+ m_myself.reset(); - } - - bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -index 9079c13..0975e8a 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -@@ -43,6 +43,7 @@ typedef struct omx_demux_packet { - } omx_demux_packet; - - class COpenMaxVideo; -+typedef boost::shared_ptr OpenMaxVideoPtr; - // an omx egl video frame - class COpenMaxVideoBuffer - { -@@ -75,7 +76,7 @@ class COpenMaxVideo - virtual ~COpenMaxVideo(); - - // Required overrides -- virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); -+ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself); - virtual void Dispose(void); - virtual int Decode(uint8_t *pData, int iSize, double dts, double pts); - virtual void Reset(void); -@@ -112,9 +113,11 @@ class COpenMaxVideo - int m_decoded_width; - int m_decoded_height; - unsigned int m_egl_buffer_count; -+ bool m_finished; - - bool m_port_settings_changed; - const char *m_pFormatName; -+ OpenMaxVideoPtr m_myself; - - std::queue m_dts_queue; - std::queue m_demux_queue; --- -2.0.4 - -From bf538d7b64ef7af80b2333412e0e6bef452bd41d Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 3 Feb 2014 23:11:31 +0000 -Subject: [PATCH 23/98] [omxcodec] Fix for aspect ratio in non-square pixel - modes - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 17 +++++++++++++++++ - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 3 +++ - 2 files changed, 20 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index 29b5bb9..7e23c87 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -63,6 +63,7 @@ COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv) - index = 0; - egl_image = 0; - texture_id = 0; -+ m_aspect_ratio = 0.0f; - } - - COpenMaxVideoBuffer::~COpenMaxVideoBuffer() -@@ -166,6 +167,8 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM - m_myself = myself; - m_decoded_width = hints.width; - m_decoded_height = hints.height; -+ m_forced_aspect_ratio = hints.forced_aspect; -+ m_aspect_ratio = hints.aspect; - - m_egl_display = g_Windowing.GetEGLDisplay(); - m_egl_context = g_Windowing.GetEGLContext(); -@@ -435,6 +438,9 @@ bool COpenMaxVideo::PortSettingsChanged() - CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err); - return false; - } -+ if (!m_forced_aspect_ratio && pixel_aspect.nX && pixel_aspect.nY) -+ m_aspect_ratio = (float)pixel_aspect.nX * port_def.format.video.nFrameWidth / -+ ((float)pixel_aspect.nY * port_def.format.video.nFrameHeight); - - if (m_port_settings_changed) - { -@@ -800,6 +806,16 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) - pDvdVideoPicture->iDisplayWidth = m_decoded_width; - pDvdVideoPicture->iDisplayHeight = m_decoded_height; - -+ if (buffer->m_aspect_ratio > 0.0 && !m_forced_aspect_ratio) -+ { -+ pDvdVideoPicture->iDisplayWidth = ((int)lrint(pDvdVideoPicture->iHeight * buffer->m_aspect_ratio)) & -3; -+ if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth) -+ { -+ pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth; -+ pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / buffer->m_aspect_ratio)) & -3; -+ } -+ } -+ - #ifdef DTS_QUEUE - if (!m_dts_queue.empty()) - { -@@ -853,6 +869,7 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone( - - // queue output omx buffer to ready list. - pthread_mutex_lock(&m_omx_output_mutex); -+ buffer->m_aspect_ratio = m_aspect_ratio; - m_omx_output_ready.push(buffer); - pthread_mutex_unlock(&m_omx_output_mutex); - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -index 0975e8a..9138a20 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -@@ -54,6 +54,7 @@ class COpenMaxVideoBuffer - OMX_BUFFERHEADERTYPE *omx_buffer; - int width; - int height; -+ float m_aspect_ratio; - int index; - - // used for egl based rendering if active -@@ -114,6 +115,8 @@ class COpenMaxVideo - int m_decoded_height; - unsigned int m_egl_buffer_count; - bool m_finished; -+ float m_aspect_ratio; -+ bool m_forced_aspect_ratio; - - bool m_port_settings_changed; - const char *m_pFormatName; --- -2.0.4 - - -From 288a46fe4df261115d5d33726ad252d1032c8445 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 3 Feb 2014 23:19:22 +0000 -Subject: [PATCH 24/98] [omxcodec] Report error when codec not enabled - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index 7e23c87..2ae722b 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -43,6 +43,7 @@ - #include - - #include "cores/omxplayer/OMXImage.h" -+#include "linux/RBP.h" - - #define DTS_QUEUE - -@@ -155,7 +156,7 @@ COpenMaxVideo::~COpenMaxVideo() - bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself) - { - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); -+ CLog::Log(LOGDEBUG, "%s::%s useomx:%d software:%d", CLASSNAME, __func__, CSettings::Get().GetBool("videoplayer.useomx"), hints.software); - #endif - - // we always qualify even if DVDFactoryCodec does this too. -@@ -232,6 +233,13 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM - break; - } - -+ if ( (m_codingType == OMX_VIDEO_CodingMPEG2 && !g_RBP.GetCodecMpg2() ) || -+ (m_codingType == OMX_VIDEO_CodingWMV && !g_RBP.GetCodecWvc1() ) ) -+ { -+ CLog::Log(LOGWARNING, "%s::%s Codec %s is not supported\n", CLASSNAME, __func__, m_pFormatName); -+ return false; -+ } -+ - // initialize OpenMAX. - if (!m_omx_decoder.Initialize("OMX.broadcom.video_decode", OMX_IndexParamVideoInit)) - { --- -2.0.4 - - -From 674f67e79653b2449ede473704296fc9def7068a Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 4 Feb 2014 17:29:37 +0000 -Subject: [PATCH 25/98] [omxcodec] Add deinterlace support - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 +- - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 106 ++++++++++++++++++--- - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 9 +- - 3 files changed, 103 insertions(+), 14 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index b8af8d0..51f56aa 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -2605,7 +2605,7 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode) - return true; - - if(m_renderMethod & RENDER_OMXEGL) -- return false; -+ return true; - - if(m_renderMethod & RENDER_EGLIMG) - return false; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index 2ae722b..fbf1458 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -33,6 +33,7 @@ - #include "utils/log.h" - #include "utils/TimeUtils.h" - #include "settings/Settings.h" -+#include "settings/MediaSettings.h" - #include "ApplicationMessenger.h" - #include "Application.h" - #include "threads/Atomics.h" -@@ -130,6 +131,10 @@ COpenMaxVideo::COpenMaxVideo() - m_port_settings_changed = false; - m_finished = false; - m_pFormatName = "omx-xxxx"; -+ -+ m_deinterlace = false; -+ m_deinterlace_request = VS_DEINTERLACEMODE_OFF; -+ m_deinterlace_second_field = false; - } - - COpenMaxVideo::~COpenMaxVideo() -@@ -140,13 +145,17 @@ COpenMaxVideo::~COpenMaxVideo() - assert(m_finished); - if (m_omx_decoder.IsInitialized()) - { -- if (m_omx_tunnel.IsInitialized()) -- m_omx_tunnel.Deestablish(); -+ if (m_omx_tunnel_decoder.IsInitialized()) -+ m_omx_tunnel_decoder.Deestablish(); -+ if (m_omx_tunnel_image_fx.IsInitialized()) -+ m_omx_tunnel_image_fx.Deestablish(); - - StopDecoder(); - - if (m_omx_egl_render.IsInitialized()) - m_omx_egl_render.Deinitialize(); -+ if (m_omx_image_fx.IsInitialized()) -+ m_omx_image_fx.Deinitialize(); - if (m_omx_decoder.IsInitialized()) - m_omx_decoder.Deinitialize(); - } -@@ -165,6 +174,8 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM - - OMX_ERRORTYPE omx_err = OMX_ErrorNone; - -+ m_deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ - m_myself = myself; - m_decoded_width = hints.width; - m_decoded_height = hints.height; -@@ -467,6 +478,49 @@ bool COpenMaxVideo::PortSettingsChanged() - return false; - } - -+ OMX_CONFIG_INTERLACETYPE interlace; -+ OMX_INIT_STRUCTURE(interlace); -+ interlace.nPortIndex = m_omx_decoder.GetOutputPort(); -+ omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace); -+ -+ if (m_deinterlace_request == VS_DEINTERLACEMODE_FORCE) -+ m_deinterlace = true; -+ else if (m_deinterlace_request == VS_DEINTERLACEMODE_OFF) -+ m_deinterlace = false; -+ else -+ m_deinterlace = interlace.eMode != OMX_InterlaceProgressive; -+ -+ CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", -+ CLASSNAME, __func__, port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight, port_def.format.video.xFramerate / (float) (1 << 16), -+ interlace.eMode, m_deinterlace); -+ -+ if (m_deinterlace) -+ { -+ if (!m_omx_image_fx.Initialize("OMX.broadcom.image_fx", OMX_IndexParamImageInit)) -+ { -+ CLog::Log(LOGERROR, "%s::%s error m_omx_image_fx.Initialize", CLASSNAME, __func__); -+ return false; -+ } -+ } -+ -+ if (m_deinterlace) -+ { -+ OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter; -+ OMX_INIT_STRUCTURE(image_filter); -+ -+ image_filter.nPortIndex = m_omx_image_fx.GetOutputPort(); -+ image_filter.nNumParams = 1; -+ image_filter.nParams[0] = 3; -+ image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced; -+ -+ omx_err = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - OMX_IndexConfigCommonImageFilterParameters omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ } -+ - OMX_CALLBACKTYPE callbacks = { NULL, NULL, DecoderFillBufferDoneCallback }; - if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit, &callbacks)) - { -@@ -487,19 +541,40 @@ bool COpenMaxVideo::PortSettingsChanged() - - m_omx_egl_render.ResetEos(); - -- CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__, -- port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight, -- port_def.format.video.xFramerate / (float)(1<<16), 0,0); -- -- m_omx_tunnel.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort()); -+ if (m_deinterlace) -+ { -+ m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort()); -+ m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort()); -+ } -+ else -+ { -+ m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort()); -+ } - -- omx_err = m_omx_tunnel.Establish(); -+ omx_err = m_omx_tunnel_decoder.Establish(); - if (omx_err != OMX_ErrorNone) - { -- CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_decoder.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err); - return false; - } - -+ if (m_deinterlace) -+ { -+ omx_err = m_omx_tunnel_image_fx.Establish(); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_image_fx.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ omx_err = m_omx_image_fx.SetStateForComponent(OMX_StateExecuting); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s - m_omx_image_fx.SetStateForComponent omx_err(0x%08x)", -+ CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ } -+ - // Obtain the information about the output port. - OMX_PARAM_PORTDEFINITIONTYPE port_format; - OMX_INIT_STRUCTURE(port_format); -@@ -724,8 +799,12 @@ void COpenMaxVideo::Reset(void) - #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); - #endif -- m_omx_egl_render.FlushAll(); -- m_omx_decoder.FlushAll(); -+ if (m_omx_egl_render.IsInitialized()) -+ m_omx_egl_render.FlushAll(); -+ if (m_omx_image_fx.IsInitialized()) -+ m_omx_image_fx.FlushAll(); -+ if (m_omx_decoder.IsInitialized()) -+ m_omx_decoder.FlushAll(); - // blow all ready video frames - while (!m_omx_output_ready.empty()) - { -@@ -825,11 +904,14 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) - } - - #ifdef DTS_QUEUE -- if (!m_dts_queue.empty()) -+ if (!m_deinterlace_second_field) - { -+ assert(!m_dts_queue.empty()); - pDvdVideoPicture->dts = m_dts_queue.front(); - m_dts_queue.pop(); - } -+ if (m_deinterlace) -+ m_deinterlace_second_field = !m_deinterlace_second_field; - #endif - // nTimeStamp is in microseconds - double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp); -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -index 9138a20..c8ad4d8 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -@@ -31,6 +31,7 @@ - #include "cores/dvdplayer/DVDStreamInfo.h" - #include "DVDVideoCodec.h" - #include "threads/Event.h" -+#include "xbmc/settings/VideoSettings.h" - - #include - #include -@@ -136,11 +137,17 @@ class COpenMaxVideo - - // Components - COMXCoreComponent m_omx_decoder; -+ COMXCoreComponent m_omx_image_fx; - COMXCoreComponent m_omx_egl_render; - -- COMXCoreTunel m_omx_tunnel; -+ COMXCoreTunel m_omx_tunnel_decoder; -+ COMXCoreTunel m_omx_tunnel_image_fx; - OMX_VIDEO_CODINGTYPE m_codingType; - -+ bool m_deinterlace; -+ EDEINTERLACEMODE m_deinterlace_request; -+ bool m_deinterlace_second_field; -+ - bool PortSettingsChanged(); - bool SendDecoderConfig(uint8_t *extradata, int extrasize); - bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize); --- -2.0.4 - - -From 2cfd4ee0c30c2b9175fb749ce75f881b525774f7 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 5 Feb 2014 11:46:33 +0000 -Subject: [PATCH 26/98] [rbp/settings] Allow av sync type to be enabled - -It works for dvdplayer ---- - system/settings/rbp.xml | 7 ------- - 1 file changed, 7 deletions(-) - -diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 28e68eb..60086d8 100644 ---- a/system/settings/rbp.xml -+++ b/system/settings/rbp.xml -@@ -1,13 +1,6 @@ - - -
-- -- -- -- false -- -- -- - - - false --- -2.0.4 - - -From 8236e9e1933ee500772cec31037669b7f6ef03f5 Mon Sep 17 00:00:00 2001 -From: Ben Avison -Date: Thu, 1 May 2014 16:28:39 +0100 -Subject: [PATCH 27/98] Improved file buffering in CArchive - -Even though memcpy is typically inlined by the compiler into byte/word loads -and stores (at least for release builds), the frequency with which 1, 2 and 4 -byte loads/stores are encountered in cases where the size is *not* -determinable at compile time is still high enough that it's worth handling -these specially. On the ARM1176JZF-S in the Raspberry Pi, this improves the -total time to open a library (in the case where it's fetched from a CArchive) -by around 4%. - -It should be noted that this code uses 16-bit and 32-bit word loads and -stores that are not necessarily aligned to their respective widths. It is -possible that there are some architectures out there which do not support -this, although all ARMs since ARMv6 have supported it (and ARMs earlier than -that are probably not powerful enough to be good targets for XBMC). ---- - xbmc/utils/Archive.h | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h -index 6ed0f8f..8506d95 100644 ---- a/xbmc/utils/Archive.h -+++ b/xbmc/utils/Archive.h -@@ -154,9 +154,17 @@ class CArchive - * than waiting until we attempt to put more data into an already full buffer */ - if (m_BufferRemain > size) - { -+ switch (size) -+ { -+ case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break; -+ case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break; -+ case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break; -+ default: - memcpy(m_BufferPos, ptr, size); - m_BufferPos += size; - m_BufferRemain -= size; -+ break; -+ } - return *this; - } - else -@@ -171,9 +179,17 @@ class CArchive - /* Note, refilling the buffer is deferred until we know we need to read more from it */ - if (m_BufferRemain >= size) - { -+ switch (size) -+ { -+ case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break; -+ case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break; -+ case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break; -+ default: - memcpy(ptr, m_BufferPos, size); - m_BufferPos += size; - m_BufferRemain -= size; -+ break; -+ } - return *this; - } - else --- -2.0.4 - - -From 89841e727efb1f027fb761d2a84bc06df41373f5 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 16 Feb 2014 17:38:05 +0000 -Subject: [PATCH 28/98] [omxcodec] Only do essential calls in texture thread - [omxcodec] Fix for files with no valid pts values. [omxcodec] Fix stall on - seek/trickplay - need to reset start flag [omxcodec] Make sure we have a - valid context when video decode starts before first fanart is decoded - [omxcodec] More care with dropping frames quickly - ---- - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 127 ++++++++++++++------- - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 14 +-- - 2 files changed, 89 insertions(+), 52 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index fbf1458..71d19af 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -55,6 +55,9 @@ - - #define CLASSNAME "COpenMaxVideo" - -+#define OMX_BUFFERFLAG_PTS_INVALID (1<<28) -+#define OMX_BUFFERFLAG_DROPPED (1<<29) -+ - COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv) - : m_omv(omv), m_refs(0) - { -@@ -120,7 +123,9 @@ void COpenMaxVideoBuffer::Sync() - - COpenMaxVideo::COpenMaxVideo() - { -+ #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); -+ #endif - pthread_mutex_init(&m_omx_output_mutex, NULL); - - m_drop_state = false; -@@ -135,6 +140,7 @@ COpenMaxVideo::COpenMaxVideo() - m_deinterlace = false; - m_deinterlace_request = VS_DEINTERLACEMODE_OFF; - m_deinterlace_second_field = false; -+ m_startframe = false; - } - - COpenMaxVideo::~COpenMaxVideo() -@@ -182,8 +188,6 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM - m_forced_aspect_ratio = hints.forced_aspect; - m_aspect_ratio = hints.aspect; - -- m_egl_display = g_Windowing.GetEGLDisplay(); -- m_egl_context = g_Windowing.GetEGLContext(); - m_egl_buffer_count = 4; - - m_codingType = OMX_VIDEO_CodingUnused; -@@ -347,6 +351,7 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM - return false; - - m_drop_state = false; -+ m_startframe = false; - - return true; - } -@@ -375,6 +380,25 @@ void COpenMaxVideo::SetDropState(bool bDrop) - CLASSNAME, __func__, bDrop); - #endif - m_drop_state = bDrop; -+ if (m_drop_state) -+ { -+ while (1) -+ { -+ COpenMaxVideoBuffer *buffer = NULL; -+ pthread_mutex_lock(&m_omx_output_mutex); -+ // fetch a output buffer and pop it off the ready list -+ if (!m_omx_output_ready.empty()) -+ { -+ buffer = m_omx_output_ready.front(); -+ m_omx_output_ready.pop(); -+ } -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ if (buffer) -+ ReturnOpenMaxBuffer(buffer); -+ else -+ break; -+ } -+ } - } - - bool COpenMaxVideo::SendDecoderConfig(uint8_t *extradata, int extrasize) -@@ -713,10 +737,13 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - - if (demuxer_bytes == 0) - omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME; -- if (pts == DVD_NOPTS_VALUE) -+ // openmax doesn't like an unknown timestamp as first frame -+ if (pts == DVD_NOPTS_VALUE && m_startframe) - omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN; -+ if (pts == DVD_NOPTS_VALUE) // hijack an omx flag to indicate there wasn't a real timestamp - it will be returned with the picture (but otherwise ignored) -+ omx_buffer->nFlags |= OMX_BUFFERFLAG_PTS_INVALID; - if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored) -- omx_buffer->nFlags |= OMX_BUFFERFLAG_DATACORRUPT; -+ omx_buffer->nFlags |= OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED; - - #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x", -@@ -731,10 +758,14 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - } - if (demuxer_bytes == 0) - { -+ m_startframe = true; - #ifdef DTS_QUEUE -- // only push if we are successful with feeding OMX_EmptyThisBuffer -- m_dts_queue.push(dts); -- assert(m_dts_queue.size() < 32); -+ if (!m_drop_state) -+ { -+ // only push if we are successful with feeding OMX_EmptyThisBuffer -+ m_dts_queue.push(dts); -+ assert(m_dts_queue.size() < 32); -+ } - #endif - if (buffer_to_free) - { -@@ -806,15 +837,8 @@ void COpenMaxVideo::Reset(void) - if (m_omx_decoder.IsInitialized()) - m_omx_decoder.FlushAll(); - // blow all ready video frames -- while (!m_omx_output_ready.empty()) -- { -- pthread_mutex_lock(&m_omx_output_mutex); -- COpenMaxVideoBuffer *pic = m_omx_output_ready.front(); -- m_omx_output_ready.pop(); -- pthread_mutex_unlock(&m_omx_output_mutex); -- // return the omx buffer back to OpenMax to fill. -- ReturnOpenMaxBuffer(pic); -- } -+ SetDropState(true); -+ SetDropState(false); - #ifdef DTS_QUEUE - while (!m_dts_queue.empty()) - m_dts_queue.pop(); -@@ -822,6 +846,7 @@ void COpenMaxVideo::Reset(void) - - while (!m_demux_queue.empty()) - m_demux_queue.pop(); -+ m_startframe = false; - } - - -@@ -914,17 +939,17 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) - m_deinterlace_second_field = !m_deinterlace_second_field; - #endif - // nTimeStamp is in microseconds -- double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp); -- pDvdVideoPicture->pts = (ts == 0) ? DVD_NOPTS_VALUE : ts; -+ pDvdVideoPicture->pts = FromOMXTime(buffer->omx_buffer->nTimeStamp); - pDvdVideoPicture->openMaxBuffer->Acquire(); - pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; -- if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT) -- pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; -+ if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_PTS_INVALID) -+ pDvdVideoPicture->pts = DVD_NOPTS_VALUE; - #if defined(OMX_DEBUG_VERBOSE) - CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__, - pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6, - pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id); - #endif -+ assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED))); - } - else - { -@@ -953,10 +978,11 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone( - COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate; - - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f", -- CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6); -+ CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x", -+ CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags); - #endif - -+ assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED))); - // queue output omx buffer to ready list. - pthread_mutex_lock(&m_omx_output_mutex); - buffer->m_aspect_ratio = m_aspect_ratio; -@@ -1000,41 +1026,60 @@ OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(void) - return(omx_err); - } - --bool COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata) -+bool COpenMaxVideo::CallbackAllocOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void *userdata) - { - COpenMaxVideo *omx = static_cast(userdata); -- return omx->AllocOMXOutputEGLTextures() == OMX_ErrorNone; -+ return omx->AllocOMXOutputEGLTextures(egl_display, egl_context) == OMX_ErrorNone; - } - --bool COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata) -+bool COpenMaxVideo::CallbackFreeOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void *userdata) - { - COpenMaxVideo *omx = static_cast(userdata); -- return omx->FreeOMXOutputEGLTextures() == OMX_ErrorNone; -+ return omx->FreeOMXOutputEGLTextures(egl_display, egl_context) == OMX_ErrorNone; - } - - bool COpenMaxVideo::AllocOMXOutputBuffers(void) - { -- return g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this); -+ pthread_mutex_lock(&m_omx_output_mutex); -+ for (size_t i = 0; i < m_egl_buffer_count; i++) -+ { -+ COpenMaxVideoBuffer *egl_buffer = new COpenMaxVideoBuffer(this); -+ egl_buffer->width = m_decoded_width; -+ egl_buffer->height = m_decoded_height; -+ egl_buffer->index = i; -+ m_omx_output_buffers.push_back(egl_buffer); -+ } -+ bool ret = g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this); -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ return ret; - } - - bool COpenMaxVideo::FreeOMXOutputBuffers(void) - { -- return g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this); -+ pthread_mutex_lock(&m_omx_output_mutex); -+ bool ret = g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this); -+ -+ for (size_t i = 0; i < m_omx_output_buffers.size(); i++) -+ { -+ COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i]; -+ delete egl_buffer; -+ } -+ -+ m_omx_output_buffers.clear(); -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ return ret; - } - --OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) -+OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context) - { - OMX_ERRORTYPE omx_err = OMX_ErrorNone; - EGLint attrib = EGL_NONE; -- COpenMaxVideoBuffer *egl_buffer; - - glActiveTexture(GL_TEXTURE0); - - for (size_t i = 0; i < m_egl_buffer_count; i++) - { -- egl_buffer = new COpenMaxVideoBuffer(this); -- egl_buffer->width = m_decoded_width; -- egl_buffer->height = m_decoded_height; -+ COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i]; - - glGenTextures(1, &egl_buffer->texture_id); - glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id); -@@ -1057,8 +1102,8 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - - // create EGLImage from texture - egl_buffer->egl_image = eglCreateImageKHR( -- m_egl_display, -- m_egl_context, -+ egl_display, -+ egl_context, - EGL_GL_TEXTURE_2D_KHR, - (EGLClientBuffer)(egl_buffer->texture_id), - &attrib); -@@ -1067,7 +1112,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage", CLASSNAME, __func__); - return(OMX_ErrorUndefined); - } -- egl_buffer->index = i; - - // tell decoder output port that it will be using EGLImage - omx_err = m_omx_egl_render.UseEGLImage( -@@ -1078,7 +1122,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - CLASSNAME, __func__, omx_err); - return(omx_err); - } -- m_omx_output_buffers.push_back(egl_buffer); - - CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d", - CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height); -@@ -1086,26 +1129,22 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) - return omx_err; - } - --OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(void) -+OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context) - { - OMX_ERRORTYPE omx_err = OMX_ErrorNone; -- COpenMaxVideoBuffer *egl_buffer; - - for (size_t i = 0; i < m_omx_output_buffers.size(); i++) - { -- egl_buffer = m_omx_output_buffers[i]; -+ COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i]; - // tell decoder output port to stop using the EGLImage - omx_err = m_omx_egl_render.FreeOutputBuffer(egl_buffer->omx_buffer); - if (omx_err != OMX_ErrorNone) - CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.FreeOutputBuffer(%p) omx_err(0x%08x)", CLASSNAME, __func__, egl_buffer->omx_buffer, omx_err); - // destroy egl_image -- eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image); -+ eglDestroyImageKHR(egl_display, egl_buffer->egl_image); - // free texture - glDeleteTextures(1, &egl_buffer->texture_id); -- delete egl_buffer; - } -- m_omx_output_buffers.clear(); -- - return omx_err; - } - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -index c8ad4d8..f234f6d 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -@@ -99,17 +99,13 @@ class COpenMaxVideo - OMX_ERRORTYPE FreeOMXInputBuffers(void); - bool AllocOMXOutputBuffers(void); - bool FreeOMXOutputBuffers(void); -- static bool CallbackAllocOMXEGLTextures(void*); -- OMX_ERRORTYPE AllocOMXOutputEGLTextures(void); -- static bool CallbackFreeOMXEGLTextures(void*); -- OMX_ERRORTYPE FreeOMXOutputEGLTextures(void); -+ static bool CallbackAllocOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void*); -+ OMX_ERRORTYPE AllocOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context); -+ static bool CallbackFreeOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void*); -+ OMX_ERRORTYPE FreeOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context); - OMX_ERRORTYPE StopDecoder(void); - OMX_ERRORTYPE ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer); - -- // EGL Resources -- EGLDisplay m_egl_display; -- EGLContext m_egl_context; -- - // Video format - bool m_drop_state; - int m_decoded_width; -@@ -148,6 +144,8 @@ class COpenMaxVideo - EDEINTERLACEMODE m_deinterlace_request; - bool m_deinterlace_second_field; - -+ bool m_startframe; -+ - bool PortSettingsChanged(); - bool SendDecoderConfig(uint8_t *extradata, int extrasize); - bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize); --- -2.0.4 - - -From 6a62251ecb1192f7400e61a9e6f3365f4964d003 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sat, 8 Mar 2014 15:36:06 +0000 -Subject: [PATCH 29/98] [hifiberry] Hack: force it to be recognised as IEC958 - capable to enable passthrough options - ---- - xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -index 8dee4bc..cc79e80 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -@@ -1296,6 +1296,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev - if (snd_card_get_name(cardNr, &cardName) == 0) - info.m_displayName = cardName; - -+ // hack: hifiberry digi doesn't correctly report as iec958 device. Needs fixing in kernel driver -+ if (info.m_displayName == "snd_rpi_hifiberry_digi") -+ info.m_deviceType = AE_DEVTYPE_IEC958; -+ - if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 && - info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") - { --- -2.0.4 - - -From dd403ddfb8710dbb5887351a2e61f6324cffacda Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 11 Mar 2014 18:50:23 +0000 -Subject: [PATCH 30/98] [dvdplayer] Use inexact seeking like omxplayer - ---- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index 87a1a9f..61b208a 100644 ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp -@@ -1888,7 +1888,11 @@ void CDVDPlayer::CheckAutoSceneSkip() - /* - * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards. - */ -+#ifdef TARGET_RASPBERRY_PI -+ m_messenger.Put(new CDVDMsgPlayerSeek(seek, true, true, true, false, true)); -+#else - m_messenger.Put(new CDVDMsgPlayerSeek(seek, true, false, true, false, true)); -+#endif - /* - * Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping - * if there was an error with seeking and it landed somewhere unexpected, perhaps back in the -@@ -1906,7 +1910,11 @@ void CDVDPlayer::CheckAutoSceneSkip() - /* - * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards. - */ -+#ifdef TARGET_RASPBERRY_PI -+ m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true)); -+#else - m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true)); -+#endif - /* - * Each commercial break is only skipped once so poorly detected commercial breaks can be - * manually re-entered. Start and end are recorded to prevent looping and to allow seeking back -@@ -3105,9 +3113,12 @@ void CDVDPlayer::UpdateClockMaster() - void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate) - { - double startpts; -+#ifndef TARGET_RASPBERRY_PI -+ /* for now, ignore accurate flag as it discards keyframes and causes corrupt frames */ - if(accurate) - startpts = pts; - else -+#endif - startpts = DVD_NOPTS_VALUE; - - /* call with demuxer pts */ --- -2.0.4 - - -From d64109414c39373c7eae15dfd01077b62d4d937f Mon Sep 17 00:00:00 2001 +From 74fd1f96569ef50e18d8b1733b2953356ce5b409 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 7 Apr 2014 18:19:32 +0100 -Subject: [PATCH 31/98] [rbp/omxplayer] When opening a stream don't try to +Subject: [PATCH 04/77] [rbp/omxplayer] When opening a stream don't try to update gui so often --- @@ -7354,1593 +976,11 @@ index e9ba7d3..0fdc3c2 100644 { g_windowManager.ProcessRenderLoop(false); if (allowCancel && dialog->IsCanceled()) --- -2.0.4 - -From 463cfd278377e55d5045ba0bcfd9d649d5e21a0c Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 7 Apr 2014 15:28:57 +0100 -Subject: [PATCH 32/98] [omxcodec] Clamp video texture at edges to avoid image - wrapping - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 51f56aa..2929a37 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -1337,6 +1337,8 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field) - GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR; - glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); -+ glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA); - --- -2.0.4 - - -From a5f0e09db5b9fcd0f7fc64f08f35267fafc89d4d Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 30 Mar 2014 15:54:34 +0100 -Subject: [PATCH 33/98] [omxplayer] Make the sharpness control act as a - sharpness control. - -This fixes scaling kernel as Mitchell Netravali, and varies sharpness over range B=[5/3,0] C=[-1/3,1/2] ---- - xbmc/cores/omxplayer/OMXPlayer.cpp | 338 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 338 insertions(+) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 53fe37d..616f88d 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -1043,6 +1043,334 @@ void CDVDPlayer::CheckBetterStream(CCurrentStream& current, CDemuxStream* stream - OpenStream(current, stream->iId, stream->source); - } - -+static void SetSharpness(float sharpness) -+{ -+ const int16_t mitchells[][32] = -+ { -+ { // B=1.66667 C=-0.33333 -+ 0, 3, 8, 15, 24, 35, 49, 55, 70, 92,100,107,109,113,113,114,114,113,113,109,107,100, 92, 70, 55, 49, 35, 24, 15, 8, 3, 0, -+ }, -+ { // B=1.64000 C=-0.32000 -+ 0, 3, 7, 14, 24, 34, 48, 54, 69, 91,100,107,111,114,116,116,116,116,114,111,107,100, 91, 69, 54, 48, 34, 24, 14, 7, 3, 0, -+ }, -+ { // B=1.61333 C=-0.30667 -+ 0, 3, 7, 14, 23, 34, 47, 53, 68, 90, 99,107,112,115,118,118,118,118,115,112,107, 99, 90, 68, 53, 47, 34, 23, 14, 7, 3, 0, -+ }, -+ { // B=1.58667 C=-0.29333 -+ 0, 2, 7, 14, 22, 33, 46, 52, 67, 89, 99,107,113,117,119,121,121,119,117,113,107, 99, 89, 67, 52, 46, 33, 22, 14, 7, 2, 0, -+ }, -+ { // B=1.56000 C=-0.28000 -+ 0, 2, 7, 13, 22, 32, 45, 51, 66, 88, 98,107,114,119,121,123,123,121,119,114,107, 98, 88, 66, 51, 45, 32, 22, 13, 7, 2, 0, -+ }, -+ { // B=1.53333 C=-0.26667 -+ 0, 2, 7, 12, 21, 31, 44, 50, 65, 87, 98,108,114,120,123,125,125,123,120,114,108, 98, 87, 65, 50, 44, 31, 21, 12, 7, 2, 0, -+ }, -+ { // B=1.50667 C=-0.25333 -+ 0, 2, 6, 12, 20, 30, 43, 49, 64, 86, 98,108,116,122,125,127,127,125,122,116,108, 98, 86, 64, 49, 43, 30, 20, 12, 6, 2, 0, -+ }, -+ { // B=1.48000 C=-0.24000 -+ 0, 2, 6, 12, 19, 29, 42, 47, 63, 85, 98,108,117,123,127,130,130,127,123,117,108, 98, 85, 63, 47, 42, 29, 19, 12, 6, 2, 0, -+ }, -+ { // B=1.45333 C=-0.22667 -+ 0, 2, 6, 11, 19, 28, 41, 46, 62, 85, 97,108,118,125,129,132,132,129,125,118,108, 97, 85, 62, 46, 41, 28, 19, 11, 6, 2, 0, -+ }, -+ { // B=1.42667 C=-0.21333 -+ 0, 2, 5, 11, 18, 28, 40, 45, 61, 84, 97,108,119,126,131,134,134,131,126,119,108, 97, 84, 61, 45, 40, 28, 18, 11, 5, 2, 0, -+ }, -+ { // B=1.40000 C=-0.20000 -+ 0, 2, 5, 10, 18, 27, 39, 44, 60, 84, 96,109,119,127,134,136,136,134,127,119,109, 96, 84, 60, 44, 39, 27, 18, 10, 5, 2, 0, -+ }, -+ { // B=1.37333 C=-0.18667 -+ 0, 1, 5, 10, 17, 26, 38, 43, 58, 82, 96,109,120,129,135,139,139,135,129,120,109, 96, 82, 58, 43, 38, 26, 17, 10, 5, 1, 0, -+ }, -+ { // B=1.34667 C=-0.17333 -+ 0, 2, 4, 10, 16, 25, 37, 42, 57, 81, 96,109,121,131,137,141,141,137,131,121,109, 96, 81, 57, 42, 37, 25, 16, 10, 4, 2, 0, -+ }, -+ { // B=1.32000 C=-0.16000 -+ 0, 1, 4, 9, 15, 24, 36, 41, 56, 81, 95,110,122,132,139,143,143,139,132,122,110, 95, 81, 56, 41, 36, 24, 15, 9, 4, 1, 0, -+ }, -+ { // B=1.29333 C=-0.14667 -+ 0, 1, 4, 8, 15, 23, 35, 40, 55, 80, 95,110,123,133,141,146,146,141,133,123,110, 95, 80, 55, 40, 35, 23, 15, 8, 4, 1, 0, -+ }, -+ { // B=1.26667 C=-0.13333 -+ 0, 1, 4, 8, 14, 22, 33, 38, 54, 79, 95,110,124,135,143,148,148,143,135,124,110, 95, 79, 54, 38, 33, 22, 14, 8, 4, 1, 0, -+ }, -+ { // B=1.24000 C=-0.12000 -+ 0, 1, 4, 7, 14, 21, 33, 37, 53, 78, 94,110,125,136,145,150,150,145,136,125,110, 94, 78, 53, 37, 33, 21, 14, 7, 4, 1, 0, -+ }, -+ { // B=1.21333 C=-0.10667 -+ 0, 1, 3, 7, 13, 20, 32, 36, 52, 77, 94,110,127,138,147,152,152,147,138,127,110, 94, 77, 52, 36, 32, 20, 13, 7, 3, 1, 0, -+ }, -+ { // B=1.18667 C=-0.09333 -+ 0, 1, 3, 7, 12, 20, 30, 35, 51, 77, 93,111,125,140,149,155,155,149,140,125,111, 93, 77, 51, 35, 30, 20, 12, 7, 3, 1, 0, -+ }, -+ { // B=1.16000 C=-0.08000 -+ 0, 1, 3, 6, 11, 19, 29, 34, 50, 76, 93,111,128,141,151,157,157,151,141,128,111, 93, 76, 50, 34, 29, 19, 11, 6, 3, 1, 0, -+ }, -+ { // B=1.13333 C=-0.06667 -+ 0, 1, 3, 5, 11, 18, 28, 33, 49, 75, 93,111,129,143,153,159,159,153,143,129,111, 93, 75, 49, 33, 28, 18, 11, 5, 3, 1, 0, -+ }, -+ { // B=1.10667 C=-0.05333 -+ 0, 1, 2, 5, 10, 17, 27, 32, 48, 74, 93,111,130,144,155,161,161,155,144,130,111, 93, 74, 48, 32, 27, 17, 10, 5, 2, 1, 0, -+ }, -+ { // B=1.08000 C=-0.04000 -+ 0, 1, 2, 5, 9, 16, 26, 31, 46, 73, 92,112,130,145,157,164,164,157,145,130,112, 92, 73, 46, 31, 26, 16, 9, 5, 2, 1, 0, -+ }, -+ { // B=1.05333 C=-0.02667 -+ 0, 0, 2, 4, 9, 15, 25, 29, 45, 72, 92,112,131,147,159,166,166,159,147,131,112, 92, 72, 45, 29, 25, 15, 9, 4, 2, 0, 0, -+ }, -+ { // B=1.02667 C=-0.01333 -+ 0, 0, 1, 4, 8, 14, 24, 28, 44, 72, 92,112,132,148,161,168,168,161,148,132,112, 92, 72, 44, 28, 24, 14, 8, 4, 1, 0, 0, -+ }, -+ { // B=1.00000 C=0.00000 -+ 0, 0, 1, 4, 7, 14, 23, 27, 43, 71, 91,112,133,150,163,170,170,163,150,133,112, 91, 71, 43, 27, 23, 14, 7, 4, 1, 0, 0, -+ }, -+ { // B=0.97333 C=0.01333 -+ 0, 0, 1, 3, 7, 12, 22, 26, 42, 70, 91,113,133,152,165,173,173,165,152,133,113, 91, 70, 42, 26, 22, 12, 7, 3, 1, 0, 0, -+ }, -+ { // B=0.94667 C=0.02667 -+ 0, 0, 1, 2, 6, 12, 21, 25, 41, 69, 90,113,135,153,167,175,175,167,153,135,113, 90, 69, 41, 25, 21, 12, 6, 2, 1, 0, 0, -+ }, -+ { // B=0.92000 C=0.04000 -+ 0, 0, 0, 2, 5, 11, 20, 24, 40, 68, 90,113,136,154,169,177,177,169,154,136,113, 90, 68, 40, 24, 20, 11, 5, 2, 0, 0, 0, -+ }, -+ { // B=0.89333 C=0.05333 -+ 0, 0, 0, 1, 5, 10, 19, 23, 39, 67, 90,114,136,156,171,179,179,171,156,136,114, 90, 67, 39, 23, 19, 10, 5, 1, 0, 0, 0, -+ }, -+ { // B=0.86667 C=0.06667 -+ 0, 0, 0, 1, 4, 9, 18, 22, 38, 66, 89,114,137,157,173,182,182,173,157,137,114, 89, 66, 38, 22, 18, 9, 4, 1, 0, 0, 0, -+ }, -+ { // B=0.84000 C=0.08000 -+ 0, 0, -1, 1, 3, 9, 17, 21, 37, 65, 89,114,138,159,175,184,184,175,159,138,114, 89, 65, 37, 21, 17, 9, 3, 1, -1, 0, 0, -+ }, -+ { // B=0.81333 C=0.09333 -+ 0, 0, -1, 0, 3, 7, 16, 19, 36, 65, 89,114,139,160,177,186,186,177,160,139,114, 89, 65, 36, 19, 16, 7, 3, 0, -1, 0, 0, -+ }, -+ { // B=0.78667 C=0.10667 -+ 0, -1, -1, 0, 2, 6, 15, 18, 35, 64, 88,115,139,162,179,188,188,179,162,139,115, 88, 64, 35, 18, 15, 6, 2, 0, -1, -1, 0, -+ }, -+ { // B=0.76000 C=0.12000 -+ 0, -1, -1, -1, 1, 6, 14, 17, 33, 63, 88,115,141,163,181,191,191,181,163,141,115, 88, 63, 33, 17, 14, 6, 1, -1, -1, -1, 0, -+ }, -+ { // B=0.73333 C=0.13333 -+ 0, -1, -1, -1, 0, 5, 13, 16, 32, 62, 87,115,142,165,183,193,193,183,165,142,115, 87, 62, 32, 16, 13, 5, 0, -1, -1, -1, 0, -+ }, -+ { // B=0.70667 C=0.14667 -+ 0, -1, -1, -2, 0, 4, 12, 15, 31, 61, 87,115,143,166,185,195,195,185,166,143,115, 87, 61, 31, 15, 12, 4, 0, -2, -1, -1, 0, -+ }, -+ { // B=0.68000 C=0.16000 -+ 0, -1, -2, -2, -1, 3, 11, 14, 30, 61, 87,116,142,168,187,197,197,187,168,142,116, 87, 61, 30, 14, 11, 3, -1, -2, -2, -1, 0, -+ }, -+ { // B=0.65333 C=0.17333 -+ 0, -1, -2, -3, -1, 2, 10, 13, 29, 60, 86,116,144,169,189,200,200,189,169,144,116, 86, 60, 29, 13, 10, 2, -1, -3, -2, -1, 0, -+ }, -+ { // B=0.62667 C=0.18667 -+ 0, -1, -3, -3, -2, 1, 9, 12, 28, 59, 86,116,145,171,191,202,202,191,171,145,116, 86, 59, 28, 12, 9, 1, -2, -3, -3, -1, 0, -+ }, -+ { // B=0.60000 C=0.20000 -+ 0, -1, -3, -3, -3, 0, 8, 10, 27, 58, 86,116,146,172,193,204,204,193,172,146,116, 86, 58, 27, 10, 8, 0, -3, -3, -3, -1, 0, -+ }, -+ { // B=0.57333 C=0.21333 -+ 0, -1, -3, -4, -3, -1, 7, 9, 26, 57, 86,116,147,174,194,207,207,194,174,147,116, 86, 57, 26, 9, 7, -1, -3, -4, -3, -1, 0, -+ }, -+ { // B=0.54667 C=0.22667 -+ 0, -2, -3, -5, -4, -1, 5, 8, 25, 57, 85,117,148,176,196,209,209,196,176,148,117, 85, 57, 25, 8, 5, -1, -4, -5, -3, -2, 0, -+ }, -+ { // B=0.52000 C=0.24000 -+ 0, -1, -4, -5, -5, -2, 4, 7, 24, 55, 85,117,149,177,199,211,211,199,177,149,117, 85, 55, 24, 7, 4, -2, -5, -5, -4, -1, 0, -+ }, -+ { // B=0.49333 C=0.25333 -+ 0, -2, -4, -5, -6, -3, 3, 6, 23, 55, 84,117,150,178,200,214,214,200,178,150,117, 84, 55, 23, 6, 3, -3, -6, -5, -4, -2, 0, -+ }, -+ { // B=0.46667 C=0.26667 -+ 0, -2, -4, -6, -6, -4, 2, 6, 22, 54, 84,118,150,180,202,216,216,202,180,150,118, 84, 54, 22, 6, 2, -4, -6, -6, -4, -2, 0, -+ }, -+ { // B=0.44000 C=0.28000 -+ 0, -2, -4, -6, -7, -5, 2, 5, 21, 53, 83,118,150,181,205,218,218,205,181,150,118, 83, 53, 21, 5, 2, -5, -7, -6, -4, -2, 0, -+ }, -+ { // B=0.41333 C=0.29333 -+ 0, -2, -4, -7, -7, -6, 0, 5, 20, 53, 83,118,152,183,207,220,220,207,183,152,118, 83, 53, 20, 5, 0, -6, -7, -7, -4, -2, 0, -+ }, -+ { // B=0.38667 C=0.30667 -+ 0, -2, -5, -7, -8, -7, -1, 4, 19, 52, 83,118,153,185,208,223,223,208,185,153,118, 83, 52, 19, 4, -1, -7, -8, -7, -5, -2, 0, -+ }, -+ { // B=0.36000 C=0.32000 -+ 0, -2, -5, -8, -8, -8, -2, 3, 19, 51, 83,118,155,186,210,225,225,210,186,155,118, 83, 51, 19, 3, -2, -8, -8, -8, -5, -2, 0, -+ }, -+ { // B=0.33333 C=0.33333 -+ 0, -2, -6, -8,-10, -8, -3, 2, 18, 50, 82,119,155,187,213,227,227,213,187,155,119, 82, 50, 18, 2, -3, -8,-10, -8, -6, -2, 0, -+ }, -+ { // B=0.32667 C=0.33667 -+ 0, -2, -6, -8,-10, -8, -3, 2, 18, 49, 82,119,155,188,213,228,228,213,188,155,119, 82, 49, 18, 2, -3, -8,-10, -8, -6, -2, 0, -+ }, -+ { // B=0.32000 C=0.34000 -+ 0, -2, -6, -8,-10, -9, -3, 2, 18, 49, 82,119,155,188,214,228,228,214,188,155,119, 82, 49, 18, 2, -3, -9,-10, -8, -6, -2, 0, -+ }, -+ { // B=0.31333 C=0.34333 -+ 0, -2, -6, -8,-10, -9, -4, 1, 18, 49, 82,119,155,188,214,229,229,214,188,155,119, 82, 49, 18, 1, -4, -9,-10, -8, -6, -2, 0, -+ }, -+ { // B=0.30667 C=0.34667 -+ 0, -2, -6, -9,-10, -9, -4, 1, 18, 49, 82,119,156,189,214,229,229,214,189,156,119, 82, 49, 18, 1, -4, -9,-10, -9, -6, -2, 0, -+ }, -+ { // B=0.30000 C=0.35000 -+ 0, -3, -5, -9,-10,-10, -4, 1, 18, 49, 82,119,156,189,215,230,230,215,189,156,119, 82, 49, 18, 1, -4,-10,-10, -9, -5, -3, 0, -+ }, -+ { // B=0.29333 C=0.35333 -+ 0, -2, -6, -9,-10,-10, -4, 1, 17, 48, 82,119,156,190,215,231,231,215,190,156,119, 82, 48, 17, 1, -4,-10,-10, -9, -6, -2, 0, -+ }, -+ { // B=0.28667 C=0.35667 -+ 0, -2, -6, -9,-11,-10, -5, 1, 17, 48, 82,119,157,190,216,231,231,216,190,157,119, 82, 48, 17, 1, -5,-10,-11, -9, -6, -2, 0, -+ }, -+ { // B=0.28000 C=0.36000 -+ 0, -3, -6, -9,-11,-10, -5, 0, 17, 48, 82,119,157,190,217,231,231,217,190,157,119, 82, 48, 17, 0, -5,-10,-11, -9, -6, -3, 0, -+ }, -+ { // B=0.27333 C=0.36333 -+ 0, -3, -6, -9,-11,-11, -5, 0, 17, 48, 82,119,157,191,217,232,232,217,191,157,119, 82, 48, 17, 0, -5,-11,-11, -9, -6, -3, 0, -+ }, -+ { // B=0.26667 C=0.36667 -+ 0, -3, -6, -9,-11,-11, -5, 0, 17, 48, 81,119,157,191,217,233,233,217,191,157,119, 81, 48, 17, 0, -5,-11,-11, -9, -6, -3, 0, -+ }, -+ { // B=0.26000 C=0.37000 -+ 0, -3, -6,-10,-11,-11, -5, 0, 16, 47, 81,120,156,191,218,233,233,218,191,156,120, 81, 47, 16, 0, -5,-11,-11,-10, -6, -3, 0, -+ }, -+ { // B=0.25333 C=0.37333 -+ 0, -3, -6, -9,-12,-11, -6, 0, 16, 47, 81,119,158,192,218,234,234,218,192,158,119, 81, 47, 16, 0, -6,-11,-12, -9, -6, -3, 0, -+ }, -+ { // B=0.24667 C=0.37667 -+ 0, -3, -6,-10,-12,-11, -6, 0, 16, 47, 81,120,157,192,219,234,234,219,192,157,120, 81, 47, 16, 0, -6,-11,-12,-10, -6, -3, 0, -+ }, -+ { // B=0.24000 C=0.38000 -+ 0, -3, -6,-10,-12,-12, -6, -1, 16, 47, 81,120,158,193,219,235,235,219,193,158,120, 81, 47, 16, -1, -6,-12,-12,-10, -6, -3, 0, -+ }, -+ { // B=0.23333 C=0.38333 -+ 0, -3, -6,-10,-12,-12, -6, -1, 16, 46, 81,120,158,193,220,236,236,220,193,158,120, 81, 46, 16, -1, -6,-12,-12,-10, -6, -3, 0, -+ }, -+ { // B=0.22667 C=0.38667 -+ 0, -3, -6,-10,-12,-12, -7, -1, 15, 47, 80,120,158,194,220,236,236,220,194,158,120, 80, 47, 15, -1, -7,-12,-12,-10, -6, -3, 0, -+ }, -+ { // B=0.22000 C=0.39000 -+ 0, -3, -6,-10,-13,-12, -7, -1, 15, 46, 80,120,159,194,221,237,237,221,194,159,120, 80, 46, 15, -1, -7,-12,-13,-10, -6, -3, 0, -+ }, -+ { // B=0.21333 C=0.39333 -+ 0, -3, -6,-10,-13,-12, -8, -1, 15, 46, 80,120,159,194,221,237,237,221,194,159,120, 80, 46, 15, -1, -8,-12,-13,-10, -6, -3, 0, -+ }, -+ { // B=0.20667 C=0.39667 -+ 0, -3, -7,-10,-13,-12, -8, -2, 15, 46, 80,120,159,194,222,238,238,222,194,159,120, 80, 46, 15, -2, -8,-12,-13,-10, -7, -3, 0, -+ }, -+ { // B=0.20000 C=0.40000 -+ 0, -3, -7,-10,-13,-13, -8, -2, 15, 45, 81,120,159,195,222,238,238,222,195,159,120, 81, 45, 15, -2, -8,-13,-13,-10, -7, -3, 0, -+ }, -+ { // B=0.19333 C=0.40333 -+ 0, -3, -7,-11,-13,-13, -8, -2, 15, 45, 81,120,160,195,223,239,239,223,195,160,120, 81, 45, 15, -2, -8,-13,-13,-11, -7, -3, 0, -+ }, -+ { // B=0.18667 C=0.40667 -+ 0, -3, -7,-10,-14,-13, -9, -2, 14, 45, 80,120,160,196,223,240,240,223,196,160,120, 80, 45, 14, -2, -9,-13,-14,-10, -7, -3, 0, -+ }, -+ { // B=0.18000 C=0.41000 -+ 0, -3, -7,-11,-13,-13, -9, -2, 14, 45, 80,120,160,196,224,240,240,224,196,160,120, 80, 45, 14, -2, -9,-13,-13,-11, -7, -3, 0, -+ }, -+ { // B=0.17333 C=0.41333 -+ 0, -3, -7,-11,-13,-14, -9, -3, 14, 45, 80,120,160,196,225,240,240,225,196,160,120, 80, 45, 14, -3, -9,-14,-13,-11, -7, -3, 0, -+ }, -+ { // B=0.16667 C=0.41667 -+ 0, -3, -7,-11,-14,-14, -9, -3, 14, 44, 80,120,161,197,225,241,241,225,197,161,120, 80, 44, 14, -3, -9,-14,-14,-11, -7, -3, 0, -+ }, -+ { // B=0.16000 C=0.42000 -+ 0, -3, -7,-11,-14,-14,-10, -3, 14, 44, 80,120,161,197,225,242,242,225,197,161,120, 80, 44, 14, -3,-10,-14,-14,-11, -7, -3, 0, -+ }, -+ { // B=0.15333 C=0.42333 -+ 0, -3, -7,-11,-14,-14,-10, -3, 13, 44, 80,120,161,197,226,242,242,226,197,161,120, 80, 44, 13, -3,-10,-14,-14,-11, -7, -3, 0, -+ }, -+ { // B=0.14667 C=0.42667 -+ 0, -3, -7,-11,-15,-14,-10, -4, 14, 43, 80,120,163,198,226,243,243,226,198,163,120, 80, 43, 14, -4,-10,-14,-15,-11, -7, -3, 0, -+ }, -+ { // B=0.14000 C=0.43000 -+ 0, -3, -7,-12,-14,-15,-10, -4, 14, 43, 80,120,163,198,227,243,243,227,198,163,120, 80, 43, 14, -4,-10,-15,-14,-12, -7, -3, 0, -+ }, -+ { // B=0.13333 C=0.43333 -+ 0, -3, -7,-12,-14,-15,-11, -4, 13, 43, 79,121,161,199,227,244,244,227,199,161,121, 79, 43, 13, -4,-11,-15,-14,-12, -7, -3, 0, -+ }, -+ { // B=0.12667 C=0.43667 -+ 0, -3, -7,-12,-14,-15,-11, -4, 13, 43, 79,120,163,199,228,245,245,228,199,163,120, 79, 43, 13, -4,-11,-15,-14,-12, -7, -3, 0, -+ }, -+ { // B=0.12000 C=0.44000 -+ 0, -3, -7,-12,-15,-15,-12, -5, 13, 43, 79,121,162,199,228,245,245,228,199,162,121, 79, 43, 13, -5,-12,-15,-15,-12, -7, -3, 0, -+ }, -+ { // B=0.11333 C=0.44333 -+ 0, -3, -7,-12,-15,-16,-11, -5, 13, 42, 79,121,162,200,229,246,246,229,200,162,121, 79, 42, 13, -5,-11,-16,-15,-12, -7, -3, 0, -+ }, -+ { // B=0.10667 C=0.44667 -+ 0, -3, -8,-12,-15,-16,-12, -5, 13, 42, 79,121,162,200,229,246,246,229,200,162,121, 79, 42, 13, -5,-12,-16,-15,-12, -8, -3, 0, -+ }, -+ { // B=0.10000 C=0.45000 -+ 0, -3, -8,-12,-16,-16,-12, -6, 13, 42, 79,121,163,200,230,247,247,230,200,163,121, 79, 42, 13, -6,-12,-16,-16,-12, -8, -3, 0, -+ }, -+ { // B=0.09333 C=0.45333 -+ 0, -3, -8,-12,-16,-16,-13, -5, 12, 42, 79,121,163,201,230,248,248,230,201,163,121, 79, 42, 12, -5,-13,-16,-16,-12, -8, -3, 0, -+ }, -+ { // B=0.08667 C=0.45667 -+ 0, -3, -8,-12,-16,-16,-13, -5, 12, 41, 79,121,163,201,231,248,248,231,201,163,121, 79, 41, 12, -5,-13,-16,-16,-12, -8, -3, 0, -+ }, -+ { // B=0.08000 C=0.46000 -+ 0, -3, -8,-12,-16,-17,-13, -6, 12, 41, 79,121,163,201,232,248,248,232,201,163,121, 79, 41, 12, -6,-13,-17,-16,-12, -8, -3, 0, -+ }, -+ { // B=0.07333 C=0.46333 -+ 0, -3, -8,-13,-16,-17,-13, -6, 12, 41, 79,121,164,202,232,249,249,232,202,164,121, 79, 41, 12, -6,-13,-17,-16,-13, -8, -3, 0, -+ }, -+ { // B=0.06667 C=0.46667 -+ 0, -3, -8,-13,-16,-17,-14, -6, 11, 41, 79,121,164,202,233,249,249,233,202,164,121, 79, 41, 11, -6,-14,-17,-16,-13, -8, -3, 0, -+ }, -+ { // B=0.06000 C=0.47000 -+ 0, -3, -8,-13,-16,-18,-14, -6, 11, 40, 79,121,164,203,233,250,250,233,203,164,121, 79, 40, 11, -6,-14,-18,-16,-13, -8, -3, 0, -+ }, -+ { // B=0.05333 C=0.47333 -+ 0, -3, -8,-13,-17,-18,-14, -6, 11, 40, 79,121,165,203,233,251,251,233,203,165,121, 79, 40, 11, -6,-14,-18,-17,-13, -8, -3, 0, -+ }, -+ { // B=0.04667 C=0.47667 -+ 0, -4, -8,-13,-17,-18,-14, -7, 11, 40, 79,121,166,203,234,251,251,234,203,166,121, 79, 40, 11, -7,-14,-18,-17,-13, -8, -4, 0, -+ }, -+ { // B=0.04000 C=0.48000 -+ 0, -4, -8,-13,-17,-18,-14, -7, 11, 40, 78,121,166,204,234,251,251,234,204,166,121, 78, 40, 11, -7,-14,-18,-17,-13, -8, -4, 0, -+ }, -+ { // B=0.03333 C=0.48333 -+ 0, -4, -8,-14,-17,-18,-15, -7, 11, 40, 78,122,164,204,235,252,252,235,204,164,122, 78, 40, 11, -7,-15,-18,-17,-14, -8, -4, 0, -+ }, -+ { // B=0.02667 C=0.48667 -+ 0, -4, -8,-14,-17,-19,-15, -7, 10, 40, 78,122,164,205,235,253,253,235,205,164,122, 78, 40, 10, -7,-15,-19,-17,-14, -8, -4, 0, -+ }, -+ { // B=0.02000 C=0.49000 -+ 0, -4, -8,-14,-17,-19,-15, -7, 10, 39, 78,122,164,205,236,253,253,236,205,164,122, 78, 39, 10, -7,-15,-19,-17,-14, -8, -4, 0, -+ }, -+ { // B=0.01333 C=0.49333 -+ 0, -4, -8,-14,-18,-19,-16, -7, 9, 40, 78,122,165,205,236,254,254,236,205,165,122, 78, 40, 9, -7,-16,-19,-18,-14, -8, -4, 0, -+ }, -+ { // B=0.00667 C=0.49667 -+ 0, -4, -9,-14,-18,-19,-15, -8, 10, 39, 78,122,166,206,236,254,254,236,206,166,122, 78, 39, 10, -8,-15,-19,-18,-14, -9, -4, 0, -+ }, -+ { // B=0.00000 C=0.50000 -+ 0, -4, -8,-14,-18,-19,-16, -8, 9, 39, 77,122,166,206,237,255,255,237,206,166,122, 77, 39, 9, -8,-16,-19,-18,-14, -8, -4, 0, -+ }, -+ }; -+ int index = (sharpness + 1.0f) * 50.0f + 0.5f; -+ if (index >=0 && index <= 100) -+ { -+ const int16_t *coef = mitchells[index]; -+ -+ char command[33*12]; -+ char response[33*12]; -+ unsigned int len = sprintf(command, "scaling_kernel "); -+ for (int i=0; i < 32; i++) { -+ if (len + 12 < sizeof command) -+ len += sprintf(command+len, "%d ", coef[i]); -+ } -+ // no interpolate flag -+ if (len + 12 < sizeof command) -+ len += sprintf(command+len, " %d", 0); -+ //printf("%i: %s\n", index, command); -+ vc_gencmd(response, sizeof response, command); -+ } -+} -+ - void CDVDPlayer::Process() - { - bool bOmxWaitVideo = false; -@@ -1175,6 +1503,8 @@ void CDVDPlayer::Process() - SetCaching(CACHESTATE_FLUSH); - - EDEINTERLACEMODE current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ float current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness; -+ SetSharpness(current_sharpness); - - while (!m_bAbortRequest) - { -@@ -1205,6 +1535,13 @@ void CDVDPlayer::Process() - current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; - } - -+ // if sharpness setting has changed, we should update it -+ if (current_sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness) -+ { -+ current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness; -+ SetSharpness(current_sharpness); -+ } -+ - m_video_fifo = (int)(100.0*(m_dvdPlayerVideo.GetDecoderBufferSize()-m_dvdPlayerVideo.GetDecoderFreeSpace())/m_dvdPlayerVideo.GetDecoderBufferSize()); - m_audio_fifo = (int)(100.0*audio_fifo/m_dvdPlayerAudio.GetCacheTotal()); - -@@ -4398,6 +4735,7 @@ void CDVDPlayer::GetRenderFeatures(std::vector &renderFeatures) - renderFeatures.push_back(RENDERFEATURE_CROP); - renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO); - renderFeatures.push_back(RENDERFEATURE_ZOOM); -+ renderFeatures.push_back(RENDERFEATURE_SHARPNESS); - } - - void CDVDPlayer::GetDeinterlaceMethods(std::vector &deinterlaceMethods) --- -2.0.4 - - -From 90f187b0cb09943283f294815caa362add7bb8c8 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 16 Apr 2014 21:18:06 +0100 -Subject: [PATCH 34/98] [omxplayer] Don't propagate 3d flags based on supported - 3d modes - ---- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++------------------------- - 1 file changed, 4 insertions(+), 25 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index af71235..0514e78 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -753,36 +753,15 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f - unsigned flags = 0; - ERenderFormat format = RENDER_FMT_BYPASS; - -+ /* figure out steremode expected based on user settings and hints */ -+ unsigned int stereo_flags = GetStereoModeFlags(GetStereoMode()); -+ - if(m_bAllowFullscreen) - { - flags |= CONF_FLAGS_FULLSCREEN; - m_bAllowFullscreen = false; // only allow on first configure - } -- -- flags |= GetStereoModeFlags(GetStereoMode()); -- -- if(flags & CONF_FLAGS_STEREO_MODE_SBS) -- { -- if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS)) -- CLog::Log(LOGNOTICE, "3DSBS movie found"); -- else -- { -- flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0); -- CLog::Log(LOGNOTICE, "3DSBS movie found but not supported"); -- } -- } -- else if(flags & CONF_FLAGS_STEREO_MODE_TAB) -- { -- if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB)) -- CLog::Log(LOGNOTICE, "3DTB movie found"); -- else -- { -- flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0); -- CLog::Log(LOGNOTICE, "3DTB movie found but not supported"); -- } -- } -- else -- CLog::Log(LOGNOTICE, "not a 3D movie"); -+ flags |= stereo_flags; - - unsigned int iDisplayWidth = width; - unsigned int iDisplayHeight = height; --- -2.0.4 - - -From c56f75a1dfedc45ccd37b076d37fbdfe971bfa1e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 17 Apr 2014 13:00:52 +0100 -Subject: [PATCH 35/98] [graphics] Don't set stereo mode based on resolution - -The resolution change should follow stereo mode ---- - xbmc/guilib/GraphicContext.cpp | 22 ---------------------- - 1 file changed, 22 deletions(-) - -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp -index 5bffdf5..7e4fdd4 100644 ---- a/xbmc/guilib/GraphicContext.cpp -+++ b/xbmc/guilib/GraphicContext.cpp -@@ -418,28 +418,6 @@ void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate) - Lock(); - - RESOLUTION_INFO info_org = CDisplaySettings::Get().GetResolutionInfo(res); -- RESOLUTION_INFO info_last = CDisplaySettings::Get().GetResolutionInfo(lastRes); -- -- RENDER_STEREO_MODE stereo_mode = m_stereoMode; -- -- // if the new mode is an actual stereo mode, switch to that -- // if the old mode was an actual stereo mode, switch to no 3d mode -- if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB) -- stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; -- else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS) -- stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; -- else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0 -- || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB) != 0) -- stereo_mode = RENDER_STEREO_MODE_OFF; -- -- if(stereo_mode != m_stereoMode) -- { -- m_stereoView = RENDER_STEREO_VIEW_OFF; -- m_stereoMode = stereo_mode; -- m_nextStereoMode = stereo_mode; -- CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode); -- } -- - RESOLUTION_INFO info_mod = GetResInfo(res); - - m_iScreenWidth = info_mod.iWidth; --- -2.0.4 - - -From bcab2450713aeda3af8e407f44c7e1d13787b60e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 17 Apr 2014 13:01:51 +0100 -Subject: [PATCH 36/98] [graphics] Allow switching to a more suitable 3D - resolution - ---- - xbmc/guilib/GraphicContext.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- - xbmc/guilib/GraphicContext.h | 1 + - 2 files changed, 41 insertions(+), 1 deletion(-) - -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp -index 7e4fdd4..886b612 100644 ---- a/xbmc/guilib/GraphicContext.cpp -+++ b/xbmc/guilib/GraphicContext.cpp -@@ -35,6 +35,7 @@ - #include "utils/JobManager.h" - #include "video/VideoReferenceClock.h" - #include "cores/IPlayer.h" -+#include - - using namespace std; - -@@ -459,6 +460,44 @@ RESOLUTION CGraphicContext::GetVideoResolution() const - return m_Resolution; - } - -+RESOLUTION CGraphicContext::Get3DVideoResolution(RENDER_STEREO_MODE mode) const -+{ -+ RESOLUTION best = m_Resolution; -+ RESOLUTION_INFO curr = CDisplaySettings::Get().GetResolutionInfo(best); -+ -+ // Find closest refresh rate -+ for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) -+ { -+ const RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo((RESOLUTION)i); -+ -+ //discard resolutions that are not the same width and height (and interlaced/3D flags) -+ //or have a too low refreshrate -+ if (info.iScreenWidth != curr.iScreenWidth -+ || info.iScreenHeight != curr.iScreenHeight -+ || info.iScreen != curr.iScreen -+ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED) -+ || fabs(info.fRefreshRate - curr.fRefreshRate) >= FLT_EPSILON) -+ continue; -+ -+ if (mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) -+ { -+ best = (RESOLUTION)i; -+ break; -+ } -+ else if (mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && info.dwFlags & D3DPRESENTFLAG_MODE3DTB) -+ { -+ best = (RESOLUTION)i; -+ break; -+ } -+ else if ((mode == RENDER_STEREO_MODE_OFF || mode == RENDER_STEREO_MODE_MONO) && !(info.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB))) -+ { -+ best = (RESOLUTION)i; -+ break; -+ } -+ } -+ return best; -+} -+ - void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res) - { - res.Overscan.left = 0; -@@ -996,7 +1035,7 @@ void CGraphicContext::Flip(const CDirtyRegionList& dirty) - if(m_stereoMode != m_nextStereoMode) - { - m_stereoMode = m_nextStereoMode; -- SetVideoResolution(GetVideoResolution(), true); -+ SetVideoResolution(Get3DVideoResolution(m_stereoMode), true); - g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET); - } - } -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h -index 0a27643..df55e92 100644 ---- a/xbmc/guilib/GraphicContext.h -+++ b/xbmc/guilib/GraphicContext.h -@@ -108,6 +108,7 @@ class CGraphicContext : public CCriticalSection, - bool IsValidResolution(RESOLUTION res); - void SetVideoResolution(RESOLUTION res, bool forceUpdate = false); - RESOLUTION GetVideoResolution() const; -+ RESOLUTION Get3DVideoResolution(RENDER_STEREO_MODE mode) const; - void ResetOverscan(RESOLUTION res, OVERSCAN &overscan); - void ResetOverscan(RESOLUTION_INFO &resinfo); - void ResetScreenParameters(RESOLUTION res); --- -2.0.4 - - -From b5ce05465707a2d497335759613fa36f2ad664a8 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 17 Apr 2014 13:38:55 +0100 -Subject: [PATCH 37/98] [3D] Support switching to 3D resolutions - -Include matching 3D flags (SBS/TAB) in the score of a resolution to switch to, to enable switching to 3d modes. -Also remove the old code that treated 3D modes differently when assigning a score. ---- - xbmc/cores/VideoRenderers/BaseRenderer.cpp | 47 +++++++++++------------------- - 1 file changed, 17 insertions(+), 30 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp -index 83c3adb..8076e76 100644 ---- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp -+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp -@@ -222,10 +222,14 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight) - RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight) - { - RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current); -+ RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode(); - - float fRefreshRate = fps; - -- float last_diff = fRefreshRate; -+ int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0); -+ if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) || -+ !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DTB)) -+ c_weight += 1000; - - // Find closest refresh rate - for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) -@@ -241,40 +245,23 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES - || info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001) - continue; - -- // For 3D choose the closest refresh rate -- if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags)) -- { -- float diff = (info.fRefreshRate - fRefreshRate); -- if(diff < 0) -- diff *= -1.0f; -+ int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0); - -- if(diff < last_diff) -- { -- last_diff = diff; -- current = (RESOLUTION)i; -- curr = info; -- } -- } -- else -- { -- int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0); -- int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0); -+ if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) || -+ !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)) -+ i_weight += 1000; - -- // Closer the better, prefer higher refresh rate if the same -- if ((i_weight < c_weight) -- || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate)) -- { -- current = (RESOLUTION)i; -- curr = info; -- } -+ // Closer the better, prefer higher refresh rate if the same -+ if ((i_weight < c_weight) -+ || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate)) -+ { -+ current = (RESOLUTION)i; -+ curr = info; -+ c_weight = i_weight; - } - } - -- // For 3D overwrite weight -- if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags)) -- weight = 0; -- else -- weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier); -+ weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier); - - return current; - } --- -2.0.4 - - -From fca774bf7f927892cd830ba830df208c0f3a4c3e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 23 Apr 2014 00:05:07 +0100 -Subject: [PATCH 38/98] [graphics] Make pixel ratio for 3d modes consistent - -Note: Use the stored stereo flags from lists of resolutions. -Use current stereo mode for current resolution. ---- - xbmc/cores/VideoRenderers/BaseRenderer.cpp | 10 ++++---- - xbmc/guilib/GraphicContext.cpp | 32 ++++++++++--------------- - xbmc/guilib/GraphicContext.h | 4 ++-- - xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 8 ------- - 4 files changed, 19 insertions(+), 35 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp -index 8076e76..beda4e9 100644 ---- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp -+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp -@@ -119,7 +119,7 @@ bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fa - - for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::Get().ResolutionInfoSize(); j++) - { -- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j); -+ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j, false); - - if (info.iScreenWidth == curr.iScreenWidth - && info.iScreenHeight == curr.iScreenHeight -@@ -179,7 +179,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight) - //get the resolution with the refreshrate closest to 60 hertz - for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) - { -- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); -+ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false); - - if (MathUtils::round_int(info.fRefreshRate) == 60 - && info.iScreenWidth == curr.iScreenWidth -@@ -200,7 +200,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight) - CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest"); - for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) - { -- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); -+ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false); - - if (info.fRefreshRate > curr.fRefreshRate - && info.iScreenWidth == curr.iScreenWidth -@@ -234,14 +234,14 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES - // Find closest refresh rate - for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) - { -- const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); -+ const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false); - - //discard resolutions that are not the same width and height (and interlaced/3D flags) - //or have a too low refreshrate - if (info.iScreenWidth != curr.iScreenWidth - || info.iScreenHeight != curr.iScreenHeight - || info.iScreen != curr.iScreen -- || (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK) -+ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED) - || info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001) - continue; - -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp -index 886b612..40a6362 100644 ---- a/xbmc/guilib/GraphicContext.cpp -+++ b/xbmc/guilib/GraphicContext.cpp -@@ -707,32 +707,26 @@ void CGraphicContext::ApplyStateBlock() - g_Windowing.ApplyStateBlock(); - } - --const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const -+const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res, bool use_current_3d /*= true*/) const - { - RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res); - -- if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) -+ if(use_current_3d ? m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL : (info.dwFlags & D3DPRESENTFLAG_MODE3DTB)) - { -- if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0) -- { -- info.fPixelRatio /= 2; -- info.iBlanking = 0; -- info.dwFlags |= D3DPRESENTFLAG_MODE3DTB; -- } -+ info.fPixelRatio /= 2; -+ info.iBlanking = 0; -+ info.dwFlags |= D3DPRESENTFLAG_MODE3DTB; - info.iHeight = (info.iHeight - info.iBlanking) / 2; - info.Overscan.top /= 2; - info.Overscan.bottom = (info.Overscan.bottom - info.iBlanking) / 2; - info.iSubtitles = (info.iSubtitles - info.iBlanking) / 2; - } - -- if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL) -+ if(use_current_3d ? m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL : (info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)) - { -- if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0) -- { -- info.fPixelRatio *= 2; -- info.iBlanking = 0; -- info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; -- } -+ info.fPixelRatio *= 2; -+ info.iBlanking = 0; -+ info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; - info.iWidth = (info.iWidth - info.iBlanking) / 2; - info.Overscan.left /= 2; - info.Overscan.right = (info.Overscan.right - info.iBlanking) / 2; -@@ -740,7 +734,7 @@ const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const - return info; - } - --void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info) -+void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info, bool use_current_3d /*= true*/) - { - RESOLUTION_INFO& curr = CDisplaySettings::Get().GetResolutionInfo(res); - curr.Overscan = info.Overscan; -@@ -750,16 +744,14 @@ void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info) - if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) - { - curr.Overscan.right = info.Overscan.right * 2 + info.iBlanking; -- if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0) -- curr.fPixelRatio /= 2.0; -+ curr.fPixelRatio /= 2.0; - } - - if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB) - { - curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking; - curr.iSubtitles = info.iSubtitles * 2 + info.iBlanking; -- if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0) -- curr.fPixelRatio *= 2.0; -+ curr.fPixelRatio *= 2.0; - } - } - -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h -index df55e92..c77f2ff 100644 ---- a/xbmc/guilib/GraphicContext.h -+++ b/xbmc/guilib/GraphicContext.h -@@ -124,8 +124,8 @@ class CGraphicContext : public CCriticalSection, - { - return GetResInfo(m_Resolution); - } -- const RESOLUTION_INFO GetResInfo(RESOLUTION res) const; -- void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info); -+ const RESOLUTION_INFO GetResInfo(RESOLUTION res, bool use_current_3d = true) const; -+ void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info, bool use_current_3d = true); - - /* \brief Get UI scaling information from a given resolution to the screen resolution. - Takes account of overscan and UI zooming. -diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp -index c58c28a..bf1e589 100644 ---- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp -+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp -@@ -449,15 +449,9 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector &r - m_desktopRes.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight); - // Also add 3D flags - if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF) -- { - m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; -- m_desktopRes.fPixelRatio *= 2.0; -- } - else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF) -- { - m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB; -- m_desktopRes.fPixelRatio *= 0.5; -- } - HDMI_PROPERTY_PARAM_T property; - property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE; - vc_tv_hdmi_get_property(&property); -@@ -600,7 +594,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v - RESOLUTION_INFO res2 = res; - res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; - res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight); -- res2.fPixelRatio *= 2.0f; - res2.iSubtitles = (int)(0.965 * res2.iHeight); - - AddUniqueResolution(res2, resolutions); -@@ -616,7 +609,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v - RESOLUTION_INFO res2 = res; - res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB; - res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight); -- res2.fPixelRatio *= 0.5f; - res2.iSubtitles = (int)(0.965 * res2.iHeight); - - AddUniqueResolution(res2, resolutions); --- -2.0.4 - - -From 3425cf937c7633b5ba935d8059de85c3e2cff7f7 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 22 Apr 2014 12:23:23 +0100 -Subject: [PATCH 39/98] [omxplayer] Make dvdplayer the default for dvd images - ---- - xbmc/cores/omxplayer/omxplayer_advancedsettings.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml -index 77c6a15..51c0daf 100644 ---- a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml -+++ b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml -@@ -2,6 +2,6 @@ - - - --- -2.0.4 - - -From 85af4bde26602bf5588af11078f0276fc9a8dacf Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sat, 26 Apr 2014 17:27:52 +0100 -Subject: [PATCH 40/98] [cec] Don't suspend pi on tv switch off - it can't wake - up - ---- - system/peripherals.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/system/peripherals.xml b/system/peripherals.xml -index a906628..9b5271a 100644 ---- a/system/peripherals.xml -+++ b/system/peripherals.xml -@@ -16,7 +16,7 @@ - - - -- -+ - - - --- -2.0.4 - - -From 33275593445d4aad1490609c077813022d06564b Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 27 Jun 2013 01:25:57 +0100 -Subject: [PATCH 42/98] [rbp/omxplayer] Do we need discontinuity handling? - -So far I've not seen what this is needed for and it does cause problems for some files. ---- - xbmc/cores/omxplayer/OMXPlayer.cpp | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 616f88d..f1c9931 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -2351,6 +2351,7 @@ static void UpdateLimits(double& minimum, double& maximum, double dts) - - void CDVDPlayer::CheckContinuity(CCurrentStream& current, DemuxPacket* pPacket) - { -+return; - if (m_playSpeed < DVD_PLAYSPEED_PAUSE) - return; - --- -2.0.4 - - -From 259fb7dbedb78a8a083cf4e21f766e79fe9b0b10 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 24 Oct 2013 00:53:26 +0100 -Subject: [PATCH 43/98] [rbp/omxplayer] Avoid marking non-monotonic timestamps - as unknown - -Following a single spurious timestamp that is in the future, -all subsequent timestamps will be marked unknown causing out of sync. ---- - xbmc/cores/omxplayer/OMXAudio.cpp | 16 ++-------------- - 1 file changed, 2 insertions(+), 14 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp -index a2f9b0c..c0c3a3f 100644 ---- a/xbmc/cores/omxplayer/OMXAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp -@@ -1211,22 +1211,10 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt - } - else - { -- if(pts == DVD_NOPTS_VALUE) -- { -+ if(pts == DVD_NOPTS_VALUE || pts == m_last_pts) - omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; -+ else - m_last_pts = pts; -- } -- else if (m_last_pts != pts) -- { -- if(pts > m_last_pts) -- m_last_pts = pts; -- else -- omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;; -- } -- else if (m_last_pts == pts) -- { -- omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN; -- } - } - - omx_buffer->nTimeStamp = ToOMXTime(val); --- -2.0.4 - - -From 64104d3983b74de984d3f4c7a69bbe13915256d5 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 13 Dec 2013 16:25:23 +0000 -Subject: [PATCH 45/98] Add time taken to resample to log - ---- - xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 7 +++++++ - xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h | 2 +- - 2 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index fe5e893..08346d2 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -@@ -2648,7 +2648,14 @@ void CActiveAE::ResampleSounds() - { - if (!(*it)->IsConverted()) - { -+ struct timespec now; -+ clock_gettime(CLOCK_MONOTONIC, &now); -+ uint64_t Start = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; -+ - ResampleSound(*it); -+ clock_gettime(CLOCK_MONOTONIC, &now); -+ uint64_t End = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; -+ CLog::Log(LOGNOTICE, "ActiveAE::%s - resample %s took %.0fms", __FUNCTION__, (*it)->m_filename.c_str(), (End-Start)*1e-6); - // only do one sound, then yield to main loop - break; - } -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h -index 01aafe3..5ab83a2 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h -@@ -57,8 +57,8 @@ class CActiveAESound : public IAESound - static int Read(void *h, uint8_t* buf, int size); - static int64_t Seek(void *h, int64_t pos, int whence); - --protected: - std::string m_filename; -+protected: - XFILE::CFile *m_pFile; - bool m_isSeekPosible; - int m_fileSize; --- -2.0.4 - - -From 6829c44375784e0ee43fb88901af699a283e09f9 Mon Sep 17 00:00:00 2001 -From: Jonathan Marshall -Date: Sat, 2 Nov 2013 23:49:17 +1300 -Subject: [PATCH 47/98] adds GetTvShowSeasons - ---- - xbmc/video/VideoDatabase.cpp | 30 ++++++++++++++++++++++++------ - xbmc/video/VideoDatabase.h | 1 + - 2 files changed, 25 insertions(+), 6 deletions(-) - -diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp -index 04785bf..d00c5b8 100644 ---- a/xbmc/video/VideoDatabase.cpp -+++ b/xbmc/video/VideoDatabase.cpp -@@ -4213,7 +4213,7 @@ bool CVideoDatabase::RemoveArtForItem(int mediaId, const MediaType &mediaType, c - return result; - } - --bool CVideoDatabase::GetTvShowSeasonArt(int showId, map > &seasonArt) -+bool CVideoDatabase::GetTvShowSeasons(int showId, map &seasons) - { - try - { -@@ -4224,19 +4224,37 @@ bool CVideoDatabase::GetTvShowSeasonArt(int showId, map - CStdString sql = PrepareSQL("select idSeason,season from seasons where idShow=%i", showId); - m_pDS2->query(sql.c_str()); - -- vector< pair > seasons; -+ seasons.clear(); - while (!m_pDS2->eof()) - { -- seasons.push_back(make_pair(m_pDS2->fv(0).get_asInt(), m_pDS2->fv(1).get_asInt())); -+ seasons.insert(make_pair(m_pDS2->fv(1).get_asInt(), m_pDS2->fv(0).get_asInt())); - m_pDS2->next(); - } - m_pDS2->close(); -+ return true; -+ } -+ catch (...) -+ { -+ CLog::Log(LOGERROR, "%s(%d) failed", __FUNCTION__, showId); -+ } -+ return false; -+} -+ -+bool CVideoDatabase::GetTvShowSeasonArt(int showId, map > &seasonArt) -+{ -+ try -+ { -+ if (NULL == m_pDB.get()) return false; -+ if (NULL == m_pDS2.get()) return false; // using dataset 2 as we're likely called in loops on dataset 1 -+ -+ map seasons; -+ GetTvShowSeasons(showId, seasons); - -- for (vector< pair >::const_iterator i = seasons.begin(); i != seasons.end(); ++i) -+ for (map::const_iterator i = seasons.begin(); i != seasons.end(); ++i) - { - map art; -- GetArtForItem(i->first, MediaTypeSeason, art); -- seasonArt.insert(make_pair(i->second,art)); -+ GetArtForItem(i->second, MediaTypeSeason, art); -+ seasonArt.insert(make_pair(i->first,art)); - } - return true; - } -diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h -index 78259ed..cbb26b7 100644 ---- a/xbmc/video/VideoDatabase.h -+++ b/xbmc/video/VideoDatabase.h -@@ -746,6 +746,7 @@ class CVideoDatabase : public CDatabase - std::string GetArtForItem(int mediaId, const MediaType &mediaType, const std::string &artType); - bool RemoveArtForItem(int mediaId, const MediaType &mediaType, const std::string &artType); - bool RemoveArtForItem(int mediaId, const MediaType &mediaType, const std::set &artTypes); -+ bool GetTvShowSeasons(int showId, std::map &seasons); - bool GetTvShowSeasonArt(int mediaId, std::map > &seasonArt); - bool GetArtTypes(const MediaType &mediaType, std::vector &artTypes); - --- -2.0.4 - - -From be4c6c018ba30a3213df5cf60ef1789560f013a5 Mon Sep 17 00:00:00 2001 -From: Jonathan Marshall -Date: Sat, 2 Nov 2013 23:50:10 +1300 -Subject: [PATCH 48/98] move AddSeason() public. - ---- - xbmc/video/VideoDatabase.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h -index cbb26b7..1a79c00 100644 ---- a/xbmc/video/VideoDatabase.h -+++ b/xbmc/video/VideoDatabase.h -@@ -757,6 +757,7 @@ class CVideoDatabase : public CDatabase - - virtual bool GetFilter(CDbUrl &videoUrl, Filter &filter, SortDescription &sorting); - -+ int AddSeason(int showID, int season); - int AddSet(const CStdString& strSet); - void ClearMovieSet(int idMovie); - void SetMovieSet(int idMovie, int idSet); -@@ -787,7 +788,6 @@ class CVideoDatabase : public CDatabase - - int AddTvShow(); - int AddMusicVideo(const CStdString& strFilenameAndPath); -- int AddSeason(int showID, int season); - - /*! \brief Adds a path to the tvshow link table. - \param idShow the id of the show. --- -2.0.4 - - -From b6c3e6eb437c31507c586b557798c609e4b30a6b Mon Sep 17 00:00:00 2001 -From: Jonathan Marshall -Date: Sat, 2 Nov 2013 23:48:24 +1300 -Subject: [PATCH 49/98] adds GetArt function to (video) scraper, allowing art - to be fetched given the video identifier. - ---- - xbmc/addons/Scraper.cpp | 38 ++++++++++++++++++++++++++++++++++++++ - xbmc/addons/Scraper.h | 3 +++ - xbmc/video/VideoInfoDownloader.cpp | 5 +++++ - xbmc/video/VideoInfoDownloader.h | 7 +++++++ - 4 files changed, 53 insertions(+) - -diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp -index b9991ae..240f46a 100644 ---- a/xbmc/addons/Scraper.cpp -+++ b/xbmc/addons/Scraper.cpp -@@ -925,6 +925,44 @@ EPISODELIST CScraper::GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl - return vcep; - } - -+// takes URL; returns true and populates art XML details on success, false otherwise -+bool CScraper::GetArt(XFILE::CCurlFile &fcurl, const std::string &id, CVideoInfoTag &video) -+{ -+ CLog::Log(LOGDEBUG, "%s: Reading art for '%s' using %s scraper " -+ "(file: '%s', content: '%s', version: '%s')", __FUNCTION__, id.c_str(), Name().c_str(), Path().c_str(), -+ ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str()); -+ -+ video.Reset(); -+ vector vcsIn; -+ CScraperUrl scurl; -+ vcsIn.push_back(id); -+ vector vcsOut = RunNoThrow("GetArt", scurl, fcurl, &vcsIn); -+ -+ // parse XML output -+ bool fRet(false); -+ for (vector::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i) -+ { -+ CXBMCTinyXML doc; -+ doc.Parse(*i, TIXML_ENCODING_UTF8); -+ if (!doc.RootElement()) -+ { -+ CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__); -+ continue; -+ } -+ -+ TiXmlHandle xhDoc(&doc); -+ TiXmlElement *pxeDetails = xhDoc.FirstChild("details").Element(); -+ if (!pxeDetails) -+ { -+ CLog::Log(LOGERROR, "%s: Invalid XML file (want
)", __FUNCTION__); -+ continue; -+ } -+ video.Load(pxeDetails, true/*fChain*/); -+ fRet = true; // but don't exit in case of chaining -+ } -+ return fRet; -+} -+ - // takes URL; returns true and populates video details on success, false otherwise - bool CScraper::GetVideoDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl, - bool fMovie/*else episode*/, CVideoInfoTag &video) -diff --git a/xbmc/addons/Scraper.h b/xbmc/addons/Scraper.h -index c7274f2..5df5296 100644 ---- a/xbmc/addons/Scraper.h -+++ b/xbmc/addons/Scraper.h -@@ -18,6 +18,8 @@ - * . - * - */ -+ -+#include - #include "addons/Addon.h" - #include "XBDateTime.h" - #include "utils/ScraperUrl.h" -@@ -146,6 +148,7 @@ class CScraper : public CAddon - CAlbum &album); - bool GetArtistDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl, - const std::string &sSearch, CArtist &artist); -+ bool GetArt(XFILE::CCurlFile &fcurl, const std::string &id, CVideoInfoTag &video); - - private: - CScraper(const CScraper &rhs); -diff --git a/xbmc/video/VideoInfoDownloader.cpp b/xbmc/video/VideoInfoDownloader.cpp -index f33ac8a..5d84734 100644 ---- a/xbmc/video/VideoInfoDownloader.cpp -+++ b/xbmc/video/VideoInfoDownloader.cpp -@@ -191,6 +191,11 @@ bool CVideoInfoDownloader::GetDetails(const CScraperUrl &url, - return m_info->GetVideoDetails(*m_http, url, true/*fMovie*/, movieDetails); - } - -+bool CVideoInfoDownloader::GetArt(const std::string &id, CVideoInfoTag &details) -+{ -+ return m_info->GetArt(*m_http, id, details); -+} -+ - bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url, - CVideoInfoTag &movieDetails, - CGUIDialogProgress *pProgress /* = NULL */) -diff --git a/xbmc/video/VideoInfoDownloader.h b/xbmc/video/VideoInfoDownloader.h -index 22ac229..75bc341 100644 ---- a/xbmc/video/VideoInfoDownloader.h -+++ b/xbmc/video/VideoInfoDownloader.h -@@ -59,6 +59,13 @@ class CVideoInfoDownloader : public CThread - - static void ShowErrorDialog(const ADDON::CScraperError &sce); - -+ /*! \brief Grab art URLs for an item with the scraper -+ \param id the unique identifier used by the scraper to describe the item. -+ \param details [out] the video info tag structure to fill with art. -+ \return true on success, false on failure. -+ */ -+ bool GetArt(const std::string &id, CVideoInfoTag &details); -+ - protected: - enum LOOKUP_STATE { DO_NOTHING = 0, - FIND_MOVIE = 1, --- -2.0.4 - - -From 0e75b28608903159462ce416a57e4d8fccb6abc2 Mon Sep 17 00:00:00 2001 -From: Jonathan Marshall -Date: Sat, 2 Nov 2013 23:53:14 +1300 -Subject: [PATCH 50/98] refresh season art if a new season is found that isn't - recorded in the database yet. Fixes #14339 - ---- - xbmc/video/VideoInfoScanner.cpp | 33 ++++++++++++++++++++++++++++++++- - xbmc/video/VideoInfoScanner.h | 2 ++ - 2 files changed, 34 insertions(+), 1 deletion(-) - -diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp -index 04e578b..b86746a 100644 ---- a/xbmc/video/VideoInfoScanner.cpp -+++ b/xbmc/video/VideoInfoScanner.cpp -@@ -1360,6 +1360,10 @@ namespace VIDEO - pDlgProgress->Progress(); - } - -+ bool updateSeasons = false; -+ map seasons; -+ m_database.GetTvShowSeasons(showInfo.m_iDbId, seasons); -+ - EPISODELIST episodes; - bool hasEpisodeGuide = false; - -@@ -1408,6 +1412,8 @@ namespace VIDEO - } - if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, true, &showInfo) < 0) - return INFO_ERROR; -+ if (seasons.find(item.GetVideoInfoTag()->m_iSeason) == seasons.end()) -+ updateSeasons = true; - continue; - } - -@@ -1537,6 +1543,8 @@ namespace VIDEO - - if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, useLocal, &showInfo) < 0) - return INFO_ERROR; -+ if (seasons.find(item.GetVideoInfoTag()->m_iSeason) == seasons.end()) -+ updateSeasons = true; - } - else - { -@@ -1545,9 +1553,27 @@ namespace VIDEO - file->cDate.GetAsLocalizedDate().c_str(), file->strTitle.c_str()); - } - } -+ if (updateSeasons) -+ UpdateSeasons(showInfo, scraper, useLocal); - return INFO_ADDED; - } - -+ void CVideoInfoScanner::UpdateSeasons(const CVideoInfoTag &showInfo, const ADDON::ScraperPtr &scraper, bool useLocal) -+ { -+ map > seasonArt; -+ m_database.GetTvShowSeasonArt(showInfo.m_iDbId, seasonArt); -+ CVideoInfoTag details; -+ CVideoInfoDownloader loader(scraper); -+ loader.GetArt(showInfo.m_strIMDBNumber, details); -+ details.m_strPath = showInfo.m_strPath; -+ GetSeasonThumbs(details, seasonArt, CVideoThumbLoader::GetArtTypes("season"), useLocal); -+ for (map >::iterator i = seasonArt.begin(); i != seasonArt.end(); ++i) -+ { -+ int seasonID = m_database.AddSeason(showInfo.m_iDbId, i->first); -+ m_database.SetArtForItem(seasonID, "season", i->second); -+ } -+ } -+ - CStdString CVideoInfoScanner::GetnfoFile(CFileItem *item, bool bGrabAny) const - { - CStdString nfoFile; -@@ -1812,6 +1838,11 @@ namespace VIDEO - } - for (int season = -1; season <= maxSeasons; season++) - { -+ // skip if we already have some art -+ map >::const_iterator i = seasonArt.find(season); -+ if (i != seasonArt.end() && !i->second.empty()) -+ continue; -+ - map art; - if (useLocal) - { -@@ -1865,7 +1896,7 @@ namespace VIDEO - art.insert(make_pair(artTypes.front(), image)); - } - -- seasonArt.insert(make_pair(season, art)); -+ seasonArt[season] = art; - } - } - -diff --git a/xbmc/video/VideoInfoScanner.h b/xbmc/video/VideoInfoScanner.h -index 7da1bf2..c764e20 100644 ---- a/xbmc/video/VideoInfoScanner.h -+++ b/xbmc/video/VideoInfoScanner.h -@@ -230,6 +230,8 @@ namespace VIDEO - */ - INFO_RET OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, const CVideoInfoTag& showInfo, CGUIDialogProgress* pDlgProgress = NULL); - -+ void UpdateSeasons(const CVideoInfoTag &showInfo, const ADDON::ScraperPtr &scraper, bool useLocal); -+ - bool EnumerateSeriesFolder(CFileItem* item, EPISODELIST& episodeList); - bool ProcessItemByVideoInfoTag(const CFileItem *item, EPISODELIST &episodeList); - --- -2.0.4 - - -From 25a70f76e35b09a7ed6f5ef4158114bdd5862a8d Mon Sep 17 00:00:00 2001 -From: Jonathan Marshall -Date: Sat, 2 Nov 2013 23:53:34 +1300 -Subject: [PATCH 51/98] REMOVEME: updated thetvdb.com scraper to support art - updates - ---- - addons/metadata.tvdb.com/tvdb.xml | 59 +++++++++++++++++++++++++-------------- - 1 file changed, 38 insertions(+), 21 deletions(-) - -diff --git a/addons/metadata.tvdb.com/tvdb.xml b/addons/metadata.tvdb.com/tvdb.xml -index 39e604d..60a0e96 100644 ---- a/addons/metadata.tvdb.com/tvdb.xml -+++ b/addons/metadata.tvdb.com/tvdb.xml -@@ -99,57 +99,74 @@ - - <Actor>.*?<Image>([^<]*)</Image>.*?<Name>([^<]*)</Name>.*?<Role>([^<]*) - -- -+ -+ -+ -+ -+ .*/(.*).zip -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>$INFO[language]</Language> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>$INFO[language]</Language> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>blank</BannerType2>[^<]*<Language></Language> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>season</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>season</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>poster</BannerType> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>poster</BannerType> - -- -- -+ -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>fanart</BannerType>[^<]*<BannerType2>([^<]*)</BannerType2>[^<]*<Colors>([^<]*)</Colors>[^<]*<Language>$INFO[language]</Language> - -- -+ - <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>fanart</BannerType>[^<]*<BannerType2>([^<]*)</BannerType2>[^<]*<Colors>([^<]*)</Colors>[^<]*<Language>((?!$INFO[language])[a-z])*</Language> - - - -- -- .*/(.*).zip -- -- -- -- - - -- -+ - - - --- -2.0.4 - - -From 379050f0c0982fc4264d89fa1143c458bf67b7ee Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sat, 22 Mar 2014 16:40:01 +0000 -Subject: [PATCH 52/98] Enable PYTHONOPTIMIZE for Pi - ---- - xbmc/interfaces/python/XBPython.cpp | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/xbmc/interfaces/python/XBPython.cpp b/xbmc/interfaces/python/XBPython.cpp -index cba242d..35a4509 100644 ---- a/xbmc/interfaces/python/XBPython.cpp -+++ b/xbmc/interfaces/python/XBPython.cpp -@@ -492,6 +492,10 @@ bool XBPython::InitializeEngine() - } - #endif - -+// Lets enable for Pi -+#if defined(TARGET_RASPBERRY_PI) -+ setenv("PYTHONOPTIMIZE", "1", 1); -+#endif - - // Darwin packs .pyo files, we need PYTHONOPTIMIZE on in order to load them. - #if defined(TARGET_DARWIN) --- -2.0.4 - - -From 818b588a0afc126f4afe0db2862d00116a50c7a7 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 28 Apr 2014 18:07:45 +0100 -Subject: [PATCH 53/98] [rpi] Make ActiveAE thread higher priority to make - audio underrun less likely - ---- - xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -index 08346d2..e302098 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp -@@ -2169,6 +2169,12 @@ void CActiveAE::LoadSettings() - bool CActiveAE::Initialize() - { - Create(); -+ -+#ifdef TARGET_RASPBERRY_PI -+ /* audio normally won't consume full cpu, so let it have prio */ -+ SetPriority(GetPriority()+1); -+#endif -+ - Message *reply; - if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT, - &reply, --- -2.0.4 - - -From af4daa73a2d9fff255013de963b6a50fdd18b45b Mon Sep 17 00:00:00 2001 +From 50339d0bf4b90ee909e0b9a6788f6dc7043b5de2 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 29 Apr 2014 15:23:22 +0100 -Subject: [PATCH 54/98] [ffmpeg] Speed up wtv index creation +Subject: [PATCH 05/77] [ffmpeg] Speed up wtv index creation The index creation is O(N^2) with number of entries (typically thousands). On a Pi this can take more than 60 seconds to execute for a recording of a few hours. @@ -9025,14 +1065,11 @@ index 0000000..8f5f989 + } + } + } --- -2.0.4 - -From 83935c9f97b8cfffa50ac24369b203fdbfb8fe3c Mon Sep 17 00:00:00 2001 +From 420bc890afead12f3315e660c77860bc5744242d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 8 Jul 2014 15:18:47 +0100 -Subject: [PATCH 55/98] ffmpeg: Add armv6 acceleration for imdct/fft used by +Subject: [PATCH 06/77] ffmpeg: Add armv6 acceleration for imdct/fft used by ac3/aac armv6: Accelerate ff_imdct_half for general case (mdct_bits != 6) @@ -9922,1906 +1959,8829 @@ index 0000000..db0118f + */ +-- +1.9.3 --- -2.0.4 - -From a9d341b74cdcc6ca9498e959c354dd126ef0e1e8 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 12 May 2014 23:06:43 +0100 -Subject: [PATCH 56/98] [omxcodec] Updates to work better with dropping and - lateness detection +From 472c348860f3aa6b39339dfea7e1a61a76ad9a45 Mon Sep 17 00:00:00 2001 +From: Jonathan Marshall +Date: Sat, 2 Nov 2013 23:49:17 +1300 +Subject: [PATCH 07/77] adds GetTvShowSeasons --- - .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 5 ++ - .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 1 + - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 97 +++++++++++++++++----- - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 9 +- - 4 files changed, 86 insertions(+), 26 deletions(-) + xbmc/video/VideoDatabase.cpp | 30 ++++++++++++++++++++++++------ + xbmc/video/VideoDatabase.h | 1 + + 2 files changed, 25 insertions(+), 6 deletions(-) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -index ef10555..8323497 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp -@@ -91,4 +91,9 @@ bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture) - return m_omx_decoder->ClearPicture(pDvdVideoPicture); +diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp +index 6ed419d..131b598 100644 +--- a/xbmc/video/VideoDatabase.cpp ++++ b/xbmc/video/VideoDatabase.cpp +@@ -4213,7 +4213,7 @@ bool CVideoDatabase::RemoveArtForItem(int mediaId, const MediaType &mediaType, c + return result; } -+bool CDVDVideoCodecOpenMax::GetCodecStats(double &pts, int &droppedPics) +-bool CVideoDatabase::GetTvShowSeasonArt(int showId, map > &seasonArt) ++bool CVideoDatabase::GetTvShowSeasons(int showId, map &seasons) + { + try + { +@@ -4224,19 +4224,37 @@ bool CVideoDatabase::GetTvShowSeasonArt(int showId, map + CStdString sql = PrepareSQL("select idSeason,season from seasons where idShow=%i", showId); + m_pDS2->query(sql.c_str()); + +- vector< pair > seasons; ++ seasons.clear(); + while (!m_pDS2->eof()) + { +- seasons.push_back(make_pair(m_pDS2->fv(0).get_asInt(), m_pDS2->fv(1).get_asInt())); ++ seasons.insert(make_pair(m_pDS2->fv(1).get_asInt(), m_pDS2->fv(0).get_asInt())); + m_pDS2->next(); + } + m_pDS2->close(); ++ return true; ++ } ++ catch (...) ++ { ++ CLog::Log(LOGERROR, "%s(%d) failed", __FUNCTION__, showId); ++ } ++ return false; ++} ++ ++bool CVideoDatabase::GetTvShowSeasonArt(int showId, map > &seasonArt) +{ -+ return m_omx_decoder->GetCodecStats(pts, droppedPics); ++ try ++ { ++ if (NULL == m_pDB.get()) return false; ++ if (NULL == m_pDS2.get()) return false; // using dataset 2 as we're likely called in loops on dataset 1 ++ ++ map seasons; ++ GetTvShowSeasons(showId, seasons); + +- for (vector< pair >::const_iterator i = seasons.begin(); i != seasons.end(); ++i) ++ for (map::const_iterator i = seasons.begin(); i != seasons.end(); ++i) + { + map art; +- GetArtForItem(i->first, MediaTypeSeason, art); +- seasonArt.insert(make_pair(i->second,art)); ++ GetArtForItem(i->second, MediaTypeSeason, art); ++ seasonArt.insert(make_pair(i->first,art)); + } + return true; + } +diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h +index 78259ed..cbb26b7 100644 +--- a/xbmc/video/VideoDatabase.h ++++ b/xbmc/video/VideoDatabase.h +@@ -746,6 +746,7 @@ class CVideoDatabase : public CDatabase + std::string GetArtForItem(int mediaId, const MediaType &mediaType, const std::string &artType); + bool RemoveArtForItem(int mediaId, const MediaType &mediaType, const std::string &artType); + bool RemoveArtForItem(int mediaId, const MediaType &mediaType, const std::set &artTypes); ++ bool GetTvShowSeasons(int showId, std::map &seasons); + bool GetTvShowSeasonArt(int mediaId, std::map > &seasonArt); + bool GetArtTypes(const MediaType &mediaType, std::vector &artTypes); + + +From 4873479f1b979e3e42de7f425645b8047748525d Mon Sep 17 00:00:00 2001 +From: Jonathan Marshall +Date: Sat, 2 Nov 2013 23:50:10 +1300 +Subject: [PATCH 08/77] move AddSeason() public. + +--- + xbmc/video/VideoDatabase.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h +index cbb26b7..1a79c00 100644 +--- a/xbmc/video/VideoDatabase.h ++++ b/xbmc/video/VideoDatabase.h +@@ -757,6 +757,7 @@ class CVideoDatabase : public CDatabase + + virtual bool GetFilter(CDbUrl &videoUrl, Filter &filter, SortDescription &sorting); + ++ int AddSeason(int showID, int season); + int AddSet(const CStdString& strSet); + void ClearMovieSet(int idMovie); + void SetMovieSet(int idMovie, int idSet); +@@ -787,7 +788,6 @@ class CVideoDatabase : public CDatabase + + int AddTvShow(); + int AddMusicVideo(const CStdString& strFilenameAndPath); +- int AddSeason(int showID, int season); + + /*! \brief Adds a path to the tvshow link table. + \param idShow the id of the show. + +From 8d4bf50d6ec30ae5760bfc08ce63198775b55399 Mon Sep 17 00:00:00 2001 +From: Jonathan Marshall +Date: Sat, 2 Nov 2013 23:48:24 +1300 +Subject: [PATCH 09/77] adds GetArt function to (video) scraper, allowing art + to be fetched given the video identifier. + +--- + xbmc/addons/Scraper.cpp | 38 ++++++++++++++++++++++++++++++++++++++ + xbmc/addons/Scraper.h | 3 +++ + xbmc/video/VideoInfoDownloader.cpp | 5 +++++ + xbmc/video/VideoInfoDownloader.h | 7 +++++++ + 4 files changed, 53 insertions(+) + +diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp +index 76d5248..f3f2930 100644 +--- a/xbmc/addons/Scraper.cpp ++++ b/xbmc/addons/Scraper.cpp +@@ -924,6 +924,44 @@ EPISODELIST CScraper::GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl + return vcep; + } + ++// takes URL; returns true and populates art XML details on success, false otherwise ++bool CScraper::GetArt(XFILE::CCurlFile &fcurl, const std::string &id, CVideoInfoTag &video) ++{ ++ CLog::Log(LOGDEBUG, "%s: Reading art for '%s' using %s scraper " ++ "(file: '%s', content: '%s', version: '%s')", __FUNCTION__, id.c_str(), Name().c_str(), Path().c_str(), ++ ADDON::TranslateContent(Content()).c_str(), Version().asString().c_str()); ++ ++ video.Reset(); ++ vector vcsIn; ++ CScraperUrl scurl; ++ vcsIn.push_back(id); ++ vector vcsOut = RunNoThrow("GetArt", scurl, fcurl, &vcsIn); ++ ++ // parse XML output ++ bool fRet(false); ++ for (vector::const_iterator i = vcsOut.begin(); i != vcsOut.end(); ++i) ++ { ++ CXBMCTinyXML doc; ++ doc.Parse(*i, TIXML_ENCODING_UTF8); ++ if (!doc.RootElement()) ++ { ++ CLog::Log(LOGERROR, "%s: Unable to parse XML", __FUNCTION__); ++ continue; ++ } ++ ++ TiXmlHandle xhDoc(&doc); ++ TiXmlElement *pxeDetails = xhDoc.FirstChild("details").Element(); ++ if (!pxeDetails) ++ { ++ CLog::Log(LOGERROR, "%s: Invalid XML file (want
)", __FUNCTION__); ++ continue; ++ } ++ video.Load(pxeDetails, true/*fChain*/); ++ fRet = true; // but don't exit in case of chaining ++ } ++ return fRet; ++} ++ + // takes URL; returns true and populates video details on success, false otherwise + bool CScraper::GetVideoDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl, + bool fMovie/*else episode*/, CVideoInfoTag &video) +diff --git a/xbmc/addons/Scraper.h b/xbmc/addons/Scraper.h +index c7274f2..5df5296 100644 +--- a/xbmc/addons/Scraper.h ++++ b/xbmc/addons/Scraper.h +@@ -18,6 +18,8 @@ + * . + * + */ ++ ++#include + #include "addons/Addon.h" + #include "XBDateTime.h" + #include "utils/ScraperUrl.h" +@@ -146,6 +148,7 @@ class CScraper : public CAddon + CAlbum &album); + bool GetArtistDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl, + const std::string &sSearch, CArtist &artist); ++ bool GetArt(XFILE::CCurlFile &fcurl, const std::string &id, CVideoInfoTag &video); + + private: + CScraper(const CScraper &rhs); +diff --git a/xbmc/video/VideoInfoDownloader.cpp b/xbmc/video/VideoInfoDownloader.cpp +index f33ac8a..5d84734 100644 +--- a/xbmc/video/VideoInfoDownloader.cpp ++++ b/xbmc/video/VideoInfoDownloader.cpp +@@ -191,6 +191,11 @@ bool CVideoInfoDownloader::GetDetails(const CScraperUrl &url, + return m_info->GetVideoDetails(*m_http, url, true/*fMovie*/, movieDetails); + } + ++bool CVideoInfoDownloader::GetArt(const std::string &id, CVideoInfoTag &details) ++{ ++ return m_info->GetArt(*m_http, id, details); ++} ++ + bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url, + CVideoInfoTag &movieDetails, + CGUIDialogProgress *pProgress /* = NULL */) +diff --git a/xbmc/video/VideoInfoDownloader.h b/xbmc/video/VideoInfoDownloader.h +index 22ac229..75bc341 100644 +--- a/xbmc/video/VideoInfoDownloader.h ++++ b/xbmc/video/VideoInfoDownloader.h +@@ -59,6 +59,13 @@ class CVideoInfoDownloader : public CThread + + static void ShowErrorDialog(const ADDON::CScraperError &sce); + ++ /*! \brief Grab art URLs for an item with the scraper ++ \param id the unique identifier used by the scraper to describe the item. ++ \param details [out] the video info tag structure to fill with art. ++ \return true on success, false on failure. ++ */ ++ bool GetArt(const std::string &id, CVideoInfoTag &details); ++ + protected: + enum LOOKUP_STATE { DO_NOTHING = 0, + FIND_MOVIE = 1, + +From 7ee9b363f0bd7cfe77d835284a7d7c770e223e3f Mon Sep 17 00:00:00 2001 +From: Jonathan Marshall +Date: Sat, 2 Nov 2013 23:53:14 +1300 +Subject: [PATCH 10/77] refresh season art if a new season is found that isn't + recorded in the database yet. Fixes #14339 + +--- + xbmc/video/VideoInfoScanner.cpp | 33 ++++++++++++++++++++++++++++++++- + xbmc/video/VideoInfoScanner.h | 2 ++ + 2 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp +index 04e578b..b86746a 100644 +--- a/xbmc/video/VideoInfoScanner.cpp ++++ b/xbmc/video/VideoInfoScanner.cpp +@@ -1360,6 +1360,10 @@ namespace VIDEO + pDlgProgress->Progress(); + } + ++ bool updateSeasons = false; ++ map seasons; ++ m_database.GetTvShowSeasons(showInfo.m_iDbId, seasons); ++ + EPISODELIST episodes; + bool hasEpisodeGuide = false; + +@@ -1408,6 +1412,8 @@ namespace VIDEO + } + if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, true, &showInfo) < 0) + return INFO_ERROR; ++ if (seasons.find(item.GetVideoInfoTag()->m_iSeason) == seasons.end()) ++ updateSeasons = true; + continue; + } + +@@ -1537,6 +1543,8 @@ namespace VIDEO + + if (AddVideo(&item, CONTENT_TVSHOWS, file->isFolder, useLocal, &showInfo) < 0) + return INFO_ERROR; ++ if (seasons.find(item.GetVideoInfoTag()->m_iSeason) == seasons.end()) ++ updateSeasons = true; + } + else + { +@@ -1545,9 +1553,27 @@ namespace VIDEO + file->cDate.GetAsLocalizedDate().c_str(), file->strTitle.c_str()); + } + } ++ if (updateSeasons) ++ UpdateSeasons(showInfo, scraper, useLocal); + return INFO_ADDED; + } + ++ void CVideoInfoScanner::UpdateSeasons(const CVideoInfoTag &showInfo, const ADDON::ScraperPtr &scraper, bool useLocal) ++ { ++ map > seasonArt; ++ m_database.GetTvShowSeasonArt(showInfo.m_iDbId, seasonArt); ++ CVideoInfoTag details; ++ CVideoInfoDownloader loader(scraper); ++ loader.GetArt(showInfo.m_strIMDBNumber, details); ++ details.m_strPath = showInfo.m_strPath; ++ GetSeasonThumbs(details, seasonArt, CVideoThumbLoader::GetArtTypes("season"), useLocal); ++ for (map >::iterator i = seasonArt.begin(); i != seasonArt.end(); ++i) ++ { ++ int seasonID = m_database.AddSeason(showInfo.m_iDbId, i->first); ++ m_database.SetArtForItem(seasonID, "season", i->second); ++ } ++ } ++ + CStdString CVideoInfoScanner::GetnfoFile(CFileItem *item, bool bGrabAny) const + { + CStdString nfoFile; +@@ -1812,6 +1838,11 @@ namespace VIDEO + } + for (int season = -1; season <= maxSeasons; season++) + { ++ // skip if we already have some art ++ map >::const_iterator i = seasonArt.find(season); ++ if (i != seasonArt.end() && !i->second.empty()) ++ continue; ++ + map art; + if (useLocal) + { +@@ -1865,7 +1896,7 @@ namespace VIDEO + art.insert(make_pair(artTypes.front(), image)); + } + +- seasonArt.insert(make_pair(season, art)); ++ seasonArt[season] = art; + } + } + +diff --git a/xbmc/video/VideoInfoScanner.h b/xbmc/video/VideoInfoScanner.h +index 7da1bf2..c764e20 100644 +--- a/xbmc/video/VideoInfoScanner.h ++++ b/xbmc/video/VideoInfoScanner.h +@@ -230,6 +230,8 @@ namespace VIDEO + */ + INFO_RET OnProcessSeriesFolder(EPISODELIST& files, const ADDON::ScraperPtr &scraper, bool useLocal, const CVideoInfoTag& showInfo, CGUIDialogProgress* pDlgProgress = NULL); + ++ void UpdateSeasons(const CVideoInfoTag &showInfo, const ADDON::ScraperPtr &scraper, bool useLocal); ++ + bool EnumerateSeriesFolder(CFileItem* item, EPISODELIST& episodeList); + bool ProcessItemByVideoInfoTag(const CFileItem *item, EPISODELIST &episodeList); + + +From 60cf5bb235e87d2f69dbf89d359e2c581ff44b03 Mon Sep 17 00:00:00 2001 +From: Jonathan Marshall +Date: Sat, 2 Nov 2013 23:53:34 +1300 +Subject: [PATCH 11/77] REMOVEME: updated thetvdb.com scraper to support art + updates + +--- + addons/metadata.tvdb.com/tvdb.xml | 59 +++++++++++++++++++++++++-------------- + 1 file changed, 38 insertions(+), 21 deletions(-) + +diff --git a/addons/metadata.tvdb.com/tvdb.xml b/addons/metadata.tvdb.com/tvdb.xml +index f27e4fc..bdf329f 100644 +--- a/addons/metadata.tvdb.com/tvdb.xml ++++ b/addons/metadata.tvdb.com/tvdb.xml +@@ -102,57 +102,74 @@ + + <Actor>.*?<Image>([^<]*)</Image>.*?<Name>([^<]*)</Name>.*?<Role>([^<]*) + +- ++ ++ ++ ++ ++ .*/(.*).zip ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>$INFO[language]</Language> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>graphical</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>$INFO[language]</Language> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>text</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>series</BannerType>[^<]*<BannerType2>blank</BannerType2>[^<]*<Language></Language> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>season</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>season</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>$INFO[language]</Language>[^<]*[^S]*Season>([0-9]+)</Season> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>season</BannerType>[^<]*<BannerType2>seasonwide</BannerType2>[^<]*<Language>((?!$INFO[language])[a-z])*</Language>[^<]*[^S]*Season>([0-9]+)</Season> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>poster</BannerType> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>poster</BannerType> + +- +- ++ ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>fanart</BannerType>[^<]*<BannerType2>([^<]*)</BannerType2>[^<]*<Colors>([^<]*)</Colors>[^<]*<Language>$INFO[language]</Language> + +- ++ + <BannerPath>([^<]*)</BannerPath>[^<]*<BannerType>fanart</BannerType>[^<]*<BannerType2>([^<]*)</BannerType2>[^<]*<Colors>([^<]*)</Colors>[^<]*<Language>((?!$INFO[language])[a-z])*</Language> + + + +- +- .*/(.*).zip +- +- +- +- + + +- ++ + + + + +From 0d268f2c4ccf5ccce96f8b56235ce2be2c39e30e Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 2 Aug 2014 17:48:04 +0100 +Subject: [PATCH 12/77] [omx] Report decoded image name + +--- + xbmc/cores/omxplayer/OMXImage.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp +index 3fbea3b..57f69c5 100644 +--- a/xbmc/cores/omxplayer/OMXImage.cpp ++++ b/xbmc/cores/omxplayer/OMXImage.cpp +@@ -325,6 +325,7 @@ bool COMXImage::DecodeJpegToTexture(COMXImageFile *file, unsigned int width, uns + { + ret = true; + *userdata = tex; ++ CLog::Log(LOGDEBUG, "%s: decoded %s %dx%d", __func__, file->GetFilename(), width, height); + } + else + { + +From c90a0c3aceeaf3dec055ede0126eb495dcc331dc Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 14 Dec 2013 16:55:05 +0000 +Subject: [PATCH 13/77] logging: Add microsecond timer to log messages + +--- + xbmc/utils/log.cpp | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/xbmc/utils/log.cpp b/xbmc/utils/log.cpp +index 4e51166..8ed8eec 100644 +--- a/xbmc/utils/log.cpp ++++ b/xbmc/utils/log.cpp +@@ -23,6 +23,7 @@ + #include "threads/SingleLock.h" + #include "threads/Thread.h" + #include "utils/StringUtils.h" ++#include "utils/TimeUtils.cpp" + + static const char* const levelNames[] = + {"DEBUG", "INFO", "NOTICE", "WARNING", "ERROR", "SEVERE", "FATAL", "NONE"}; +@@ -195,19 +196,22 @@ void CLog::PrintDebugString(const std::string& line) + + bool CLog::WriteLogString(int logLevel, const std::string& logString) + { +- static const char* prefixFormat = "%02.2d:%02.2d:%02.2d T:%" PRIu64" %7s: "; +- ++ static const char* prefixFormat = "%02.2d:%02.2d:%02.2d %10.6f T:%" PRIu64" %7s: "; + std::string strData(logString); + /* fixup newline alignment, number of spaces should equal prefix length */ + StringUtils::Replace(strData, "\n", "\n "); + + int hour, minute, second; + s_globals.m_platform.GetCurrentLocalTime(hour, minute, second); +- ++ ++ struct timespec now; ++ clock_gettime(CLOCK_MONOTONIC, &now); ++ float Now = now.tv_sec + now.tv_nsec * 1e-9; ++ + strData = StringUtils::Format(prefixFormat, + hour, + minute, +- second, ++ second, Now, + (uint64_t)CThread::GetCurrentThreadId(), + levelNames[logLevel]) + strData; + + +From 3d1e720a7b09297dacb25e5bd71c7b3e6f4459f1 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 14 Jan 2014 18:04:07 +0000 +Subject: [PATCH 16/77] [rbp] Allow ALSA to be chosen in addition to Pi sink + +Needs --enable-alsa in ./configure step and alsa support on platform +--- + configure.in | 1 - + tools/depends/target/Makefile | 5 +++-- + xbmc/cores/AudioEngine/AESinkFactory.cpp | 15 ++++++++++++++- + 3 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/configure.in b/configure.in +index e2b2a51..fcb7b62 100644 +--- a/configure.in ++++ b/configure.in +@@ -711,7 +711,6 @@ case $use_platform in + use_arch="arm" + use_cpu=arm1176jzf-s + use_hardcoded_tables="yes" +- use_alsa="no" + ARCH="arm" + AC_DEFINE(HAS_EGLGLES, [1], [Define if supporting EGL based GLES Framebuffer]) + USE_OMXLIB=1; AC_DEFINE([HAVE_OMXLIB],[1],["Define to 1 if OMX libs is enabled"]) +diff --git a/tools/depends/target/Makefile b/tools/depends/target/Makefile +index f5374b2..73a939c 100644 +--- a/tools/depends/target/Makefile ++++ b/tools/depends/target/Makefile +@@ -58,10 +58,11 @@ LINUX_SYSTEM_LIBS= + ifeq ($(OS),linux) + #not for raspberry pi + ifneq ($(TARGET_PLATFORM),raspberry-pi) +- DEPENDS += alsa-lib libsdl linux-system-libs +- ALSA_LIB = alsa-lib ++ DEPENDS += libsdl linux-system-libs + LINUX_SYSTEM_LIBS = linux-system-libs + endif ++ DEPENDS += alsa-lib ++ ALSA_LIB = alsa-lib + FFMPEG_DEPENDS = gnutls + endif + +diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp +index e42d973..715b4f1 100644 +--- a/xbmc/cores/AudioEngine/AESinkFactory.cpp ++++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp +@@ -27,6 +27,7 @@ + #include "Sinks/AESinkAUDIOTRACK.h" + #elif defined(TARGET_RASPBERRY_PI) + #include "Sinks/AESinkPi.h" ++ #include "Sinks/AESinkALSA.h" + #elif defined(TARGET_DARWIN_IOS) + #include "Sinks/AESinkDARWINIOS.h" + #elif defined(TARGET_DARWIN_OSX) +@@ -66,6 +67,7 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver) + driver == "AUDIOTRACK" || + #elif defined(TARGET_RASPBERRY_PI) + driver == "PI" || ++ driver == "ALSA" || + #elif defined(TARGET_DARWIN_IOS) + driver == "DARWINIOS" || + #elif defined(TARGET_DARWIN_OSX) +@@ -105,7 +107,12 @@ IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAud + #elif defined(TARGET_ANDROID) + sink = new CAESinkAUDIOTRACK(); + #elif defined(TARGET_RASPBERRY_PI) ++ if (driver == "PI") + sink = new CAESinkPi(); ++ #if defined(HAS_ALSA) ++ if (driver == "ALSA") ++ sink = new CAESinkALSA(); ++ #endif + #elif defined(TARGET_DARWIN_IOS) + sink = new CAESinkDARWINIOS(); + #elif defined(TARGET_DARWIN_OSX) +@@ -196,7 +203,13 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force) + CAESinkPi::EnumerateDevicesEx(info.m_deviceInfoList, force); + if(!info.m_deviceInfoList.empty()) + list.push_back(info); +- ++ #if defined(HAS_ALSA) ++ info.m_deviceInfoList.clear(); ++ info.m_sinkName = "ALSA"; ++ CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force); ++ if(!info.m_deviceInfoList.empty()) ++ list.push_back(info); ++ #endif + #elif defined(TARGET_DARWIN_IOS) + + info.m_deviceInfoList.clear(); + +From ede35f9c20d4468b43987b49182f6f73e5d75882 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 8 Mar 2014 15:36:06 +0000 +Subject: [PATCH 17/77] [hifiberry] Hack: force it to be recognised as IEC958 + capable to enable passthrough options + +--- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index a464b4b..7eba389 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -1296,6 +1296,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev + if (snd_card_get_name(cardNr, &cardName) == 0) + info.m_displayName = cardName; + ++ // hack: hifiberry digi doesn't correctly report as iec958 device. Needs fixing in kernel driver ++ if (info.m_displayName == "snd_rpi_hifiberry_digi") ++ info.m_deviceType = AE_DEVTYPE_IEC958; ++ + if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 && + info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") + { + +From 205678b81f1602bfa11de7f4993a3e94d0bd93ab Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 11 Dec 2013 17:21:54 +0000 +Subject: [PATCH 18/77] Move the reference-counting of Begin and End calls from + DX and GL source files into GUIFontTTF.cpp. + +--- + xbmc/guilib/GUIFontTTF.cpp | 21 ++++++ + xbmc/guilib/GUIFontTTF.h | 6 +- + xbmc/guilib/GUIFontTTFDX.cpp | 79 ++++++++++------------ + xbmc/guilib/GUIFontTTFDX.h | 4 +- + xbmc/guilib/GUIFontTTFGL.cpp | 154 ++++++++++++++++++++----------------------- + xbmc/guilib/GUIFontTTFGL.h | 4 +- + 6 files changed, 135 insertions(+), 133 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index 008c7ae4..e507833 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -308,6 +308,27 @@ bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float as + return true; + } + ++void CGUIFontTTFBase::Begin() ++{ ++ if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin()) ++ { ++ m_vertex_count = 0; ++ } ++ // Keep track of the nested begin/end calls. ++ m_nestedBeginCount++; ++} ++ ++void CGUIFontTTFBase::End() ++{ ++ if (m_nestedBeginCount == 0) ++ return; ++ ++ if (--m_nestedBeginCount > 0) ++ return; ++ ++ LastEnd(); ++} ++ + void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling) + { + Begin(); +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index 4501dbd..df54a5d 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -77,8 +77,8 @@ class CGUIFontTTFBase + + bool Load(const CStdString& strFilename, float height = 20.0f, float aspect = 1.0f, float lineSpacing = 1.0f, bool border = false); + +- virtual void Begin() = 0; +- virtual void End() = 0; ++ void Begin(); ++ void End(); + + const CStdString& GetFileName() const { return m_strFileName; }; + +@@ -168,6 +168,8 @@ class CGUIFontTTFBase + CStdString m_strFileName; + + private: ++ virtual bool FirstBegin() = 0; ++ virtual void LastEnd() = 0; + CGUIFontTTFBase(const CGUIFontTTFBase&); + CGUIFontTTFBase& operator=(const CGUIFontTTFBase&); + int m_referenceCount; +diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp +index e3eba24..2f90668 100644 +--- a/xbmc/guilib/GUIFontTTFDX.cpp ++++ b/xbmc/guilib/GUIFontTTFDX.cpp +@@ -51,65 +51,56 @@ CGUIFontTTFDX::~CGUIFontTTFDX(void) + free(m_index); + } + +-void CGUIFontTTFDX::Begin() ++bool CGUIFontTTFDX::FirstBegin() + { + LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice(); + + if (pD3DDevice == NULL) ++ { + CLog::Log(LOGERROR, __FUNCTION__" - failed to get Direct3D device"); ++ return false; ++ } + +- if (m_nestedBeginCount == 0 && pD3DDevice != NULL && m_texture != NULL) ++ int unit = 0; ++ // just have to blit from our texture. ++ m_texture->BindToUnit(unit); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); ++ unit++; ++ ++ if(g_Windowing.UseLimitedColor()) + { +- int unit = 0; +- // just have to blit from our texture. +- m_texture->BindToUnit(unit); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse +- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD ); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ; ++ pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) ); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR ); + unit++; +- +- if(g_Windowing.UseLimitedColor()) +- { +- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP , D3DTOP_ADD ); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ; +- pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) ); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR ); +- unit++; +- } +- +- // no other texture stages needed +- pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE); +- pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE); +- +- pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); +- pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); +- pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); +- pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); +- pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); +- pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); +- pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); +- pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE); +- +- pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); +- m_vertex_count = 0; + } + +- // Keep track of the nested begin/end calls. +- m_nestedBeginCount++; ++ // no other texture stages needed ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE); ++ pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE); ++ ++ pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); ++ pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); ++ pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); ++ pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); ++ pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); ++ pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); ++ pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); ++ pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE); ++ ++ pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); ++ return true; + } + +-void CGUIFontTTFDX::End() ++void CGUIFontTTFDX::LastEnd() + { + LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice(); + +- if (m_nestedBeginCount == 0) +- return; +- +- if (--m_nestedBeginCount > 0) +- return; +- + if (m_vertex_count == 0) + return; + +diff --git a/xbmc/guilib/GUIFontTTFDX.h b/xbmc/guilib/GUIFontTTFDX.h +index 0431085..17dfefe 100644 +--- a/xbmc/guilib/GUIFontTTFDX.h ++++ b/xbmc/guilib/GUIFontTTFDX.h +@@ -41,8 +41,8 @@ class CGUIFontTTFDX : public CGUIFontTTFBase + CGUIFontTTFDX(const CStdString& strFileName); + virtual ~CGUIFontTTFDX(void); + +- virtual void Begin(); +- virtual void End(); ++ virtual bool FirstBegin(); ++ virtual void LastEnd(); + + protected: + virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index 6a8291b..97853fd 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -53,108 +53,96 @@ CGUIFontTTFGL::~CGUIFontTTFGL(void) + { + } + +-void CGUIFontTTFGL::Begin() ++bool CGUIFontTTFGL::FirstBegin() + { +- if (m_nestedBeginCount == 0 && m_texture != NULL) ++ if (m_textureStatus == TEXTURE_REALLOCATED) + { +- if (m_textureStatus == TEXTURE_REALLOCATED) +- { +- if (glIsTexture(m_nTexture)) +- g_TextureManager.ReleaseHwTexture(m_nTexture); +- m_textureStatus = TEXTURE_VOID; +- } +- +- if (m_textureStatus == TEXTURE_VOID) +- { +- // Have OpenGL generate a texture object handle for us +- glGenTextures(1, (GLuint*) &m_nTexture); ++ if (glIsTexture(m_nTexture)) ++ g_TextureManager.ReleaseHwTexture(m_nTexture); ++ m_textureStatus = TEXTURE_VOID; ++ } + +- // Bind the texture object +- glBindTexture(GL_TEXTURE_2D, m_nTexture); ++ if (m_textureStatus == TEXTURE_VOID) ++ { ++ // Have OpenGL generate a texture object handle for us ++ glGenTextures(1, (GLuint*) &m_nTexture); ++ ++ // Bind the texture object ++ glBindTexture(GL_TEXTURE_2D, m_nTexture); + #ifdef HAS_GL +- glEnable(GL_TEXTURE_2D); ++ glEnable(GL_TEXTURE_2D); + #endif +- // Set the texture's stretching properties +- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ++ // Set the texture's stretching properties ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +- // Set the texture image -- THIS WORKS, so the pixels must be wrong. +- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0, +- GL_ALPHA, GL_UNSIGNED_BYTE, 0); +- +- VerifyGLState(); +- m_textureStatus = TEXTURE_UPDATED; +- } ++ // Set the texture image -- THIS WORKS, so the pixels must be wrong. ++ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0, ++ GL_ALPHA, GL_UNSIGNED_BYTE, 0); + +- if (m_textureStatus == TEXTURE_UPDATED) +- { +- glBindTexture(GL_TEXTURE_2D, m_nTexture); +- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1, GL_ALPHA, GL_UNSIGNED_BYTE, +- m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch()); +- glDisable(GL_TEXTURE_2D); +- +- m_updateY1 = m_updateY2 = 0; +- m_textureStatus = TEXTURE_READY; +- } ++ VerifyGLState(); ++ m_textureStatus = TEXTURE_UPDATED; ++ } + +- // Turn Blending On +- glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); +- glEnable(GL_BLEND); ++ if (m_textureStatus == TEXTURE_UPDATED) ++ { ++ glBindTexture(GL_TEXTURE_2D, m_nTexture); ++ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, m_updateY1, m_texture->GetWidth(), m_updateY2 - m_updateY1, GL_ALPHA, GL_UNSIGNED_BYTE, ++ m_texture->GetPixels() + m_updateY1 * m_texture->GetPitch()); ++ glDisable(GL_TEXTURE_2D); ++ ++ m_updateY1 = m_updateY2 = 0; ++ m_textureStatus = TEXTURE_READY; ++ } ++ ++ // Turn Blending On ++ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); ++ glEnable(GL_BLEND); + #ifdef HAS_GL +- glEnable(GL_TEXTURE_2D); ++ glEnable(GL_TEXTURE_2D); + #endif +- glBindTexture(GL_TEXTURE_2D, m_nTexture); ++ glBindTexture(GL_TEXTURE_2D, m_nTexture); + + #ifdef HAS_GL +- glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); +- glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE); +- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); +- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); +- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); +- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0); +- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); +- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); +- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); +- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +- VerifyGLState(); ++ glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE); ++ glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE); ++ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); ++ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); ++ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); ++ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0); ++ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); ++ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); ++ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); ++ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); ++ VerifyGLState(); ++ ++ if(g_Windowing.UseLimitedColor()) ++ { ++ glActiveTexture(GL_TEXTURE1); ++ glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind ++ glEnable(GL_TEXTURE_2D); + +- if(g_Windowing.UseLimitedColor()) +- { +- glActiveTexture(GL_TEXTURE1); +- glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind +- glEnable(GL_TEXTURE_2D); +- +- const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f}; +- glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE); +- glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba); +- glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD); +- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS); +- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT); +- glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR); +- glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR); +- glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE); +- glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS); +- VerifyGLState(); +- } ++ const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f}; ++ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE); ++ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba); ++ glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD); ++ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS); ++ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT); ++ glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR); ++ glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR); ++ glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE); ++ glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS); ++ VerifyGLState(); ++ } + + #else +- g_Windowing.EnableGUIShader(SM_FONTS); ++ g_Windowing.EnableGUIShader(SM_FONTS); + #endif +- +- m_vertex_count = 0; +- } +- // Keep track of the nested begin/end calls. +- m_nestedBeginCount++; ++ return true; + } + +-void CGUIFontTTFGL::End() ++void CGUIFontTTFGL::LastEnd() + { +- if (m_nestedBeginCount == 0) +- return; +- +- if (--m_nestedBeginCount > 0) +- return; +- + #ifdef HAS_GL + glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + +diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h +index c0bb53a..735fb3a 100644 +--- a/xbmc/guilib/GUIFontTTFGL.h ++++ b/xbmc/guilib/GUIFontTTFGL.h +@@ -41,8 +41,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase + CGUIFontTTFGL(const CStdString& strFileName); + virtual ~CGUIFontTTFGL(void); + +- virtual void Begin(); +- virtual void End(); ++ virtual bool FirstBegin(); ++ virtual void LastEnd(); + + protected: + virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); + +From 70d3e4869c1eb9a308a6ff32a1cd13958dd3f3be Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 11 Dec 2013 18:47:54 +0000 +Subject: [PATCH 19/77] Convert CGUIFontTTFBase::m_vertex to be managed as a + std::vector. + +Also retired CGUIFontTTFBase::m_vertex_count and +CGUIFontTTFBase::m_vertex_size because these can be derived from vector +member functions. +--- + xbmc/guilib/GUIFontTTF.cpp | 29 +++++------------------------ + xbmc/guilib/GUIFontTTF.h | 4 +--- + xbmc/guilib/GUIFontTTFDX.cpp | 12 ++++++------ + xbmc/guilib/GUIFontTTFGL.cpp | 12 ++++++------ + 4 files changed, 18 insertions(+), 39 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index e507833..0a80471 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -138,8 +138,7 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) + m_maxChars = 0; + m_nestedBeginCount = 0; + +- m_vertex_size = 4*1024; +- m_vertex = (SVertex*)malloc(m_vertex_size * sizeof(SVertex)); ++ m_vertex.reserve(4*1024); + + m_face = NULL; + m_stroker = NULL; +@@ -154,7 +153,6 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) + m_textureScaleX = m_textureScaleY = 0.0; + m_ellipsesWidth = m_height = 0.0f; + m_color = 0; +- m_vertex_count = 0; + m_nTexture = 0; + } + +@@ -215,9 +213,7 @@ void CGUIFontTTFBase::Clear() + g_freeTypeLibrary.ReleaseStroker(m_stroker); + m_stroker = NULL; + +- free(m_vertex); +- m_vertex = NULL; +- m_vertex_count = 0; ++ m_vertex.clear(); + } + + bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float aspect, float lineSpacing, bool border) +@@ -312,7 +308,7 @@ void CGUIFontTTFBase::Begin() + { + if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin()) + { +- m_vertex_count = 0; ++ m_vertex.clear(); + } + // Keep track of the nested begin/end calls. + m_nestedBeginCount++; +@@ -745,22 +741,9 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c + float tt = texture.y1 * m_textureScaleY; + float tb = texture.y2 * m_textureScaleY; + +- // grow the vertex buffer if required +- if(m_vertex_count >= m_vertex_size) +- { +- m_vertex_size *= 2; +- void* old = m_vertex; +- m_vertex = (SVertex*)realloc(m_vertex, m_vertex_size * sizeof(SVertex)); +- if (!m_vertex) +- { +- free(old); +- CLog::Log(LOGSEVERE, "%s: can't allocate %" PRIdS" bytes for texture", __FUNCTION__ , m_vertex_size * sizeof(SVertex)); +- return; +- } +- } +- ++ m_vertex.resize(m_vertex.size() + 4); ++ SVertex* v = &m_vertex[m_vertex.size() - 4]; + m_color = color; +- SVertex* v = m_vertex + m_vertex_count; + + unsigned char r = GET_R(color) + , g = GET_G(color) +@@ -827,8 +810,6 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c + v[3].y = y[2]; + v[3].z = z[2]; + #endif +- +- m_vertex_count+=4; + } + + // Oblique code - original taken from freetype2 (ftsynth.c) +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index df54a5d..10a7060 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -156,9 +156,7 @@ class CGUIFontTTFBase + + unsigned int m_nTexture; + +- SVertex* m_vertex; +- int m_vertex_count; +- int m_vertex_size; ++ std::vector m_vertex; + + float m_textureScaleX; + float m_textureScaleY; +diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp +index 2f90668..6ef8984 100644 +--- a/xbmc/guilib/GUIFontTTFDX.cpp ++++ b/xbmc/guilib/GUIFontTTFDX.cpp +@@ -101,17 +101,17 @@ void CGUIFontTTFDX::LastEnd() + { + LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice(); + +- if (m_vertex_count == 0) ++ if (m_vertex.size() == 0) + return; + +- unsigned index_size = m_vertex_size * 6 / 4; ++ unsigned index_size = m_vertex.capacity() * 6 / 4; + if(m_index_size < index_size) + { + uint16_t* id = (uint16_t*)calloc(index_size, sizeof(uint16_t)); + if(id == NULL) + return; + +- for(int i = 0, b = 0; i < m_vertex_size; i += 4, b += 6) ++ for(int i = 0, b = 0; i < m_vertex.capacity(); i += 4, b += 6) + { + id[b+0] = i + 0; + id[b+1] = i + 1; +@@ -140,11 +140,11 @@ void CGUIFontTTFDX::LastEnd() + + pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST + , 0 +- , m_vertex_count +- , m_vertex_count / 2 ++ , m_vertex.size() ++ , m_vertex.size() / 2 + , m_index + , D3DFMT_INDEX16 +- , m_vertex ++ , &m_vertex[0] + , sizeof(SVertex)); + pD3DDevice->SetTransform(D3DTS_WORLD, &orig); + +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index 97853fd..b76c6a5 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -146,13 +146,13 @@ void CGUIFontTTFGL::LastEnd() + #ifdef HAS_GL + glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + +- glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r)); +- glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x)); +- glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u)); ++ glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, r)); ++ glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, x)); ++ glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, u)); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); +- glDrawArrays(GL_QUADS, 0, m_vertex_count); ++ glDrawArrays(GL_QUADS, 0, m_vertex.size()); + glPopClientAttrib(); + + glActiveTexture(GL_TEXTURE1); +@@ -168,10 +168,10 @@ void CGUIFontTTFGL::LastEnd() + GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); + + // stack object until VBOs will be used +- std::vector vecVertices( 6 * (m_vertex_count / 4) ); ++ std::vector vecVertices( 6 * (m_vertex.size() / 4) ); + SVertex *vertices = &vecVertices[0]; + +- for (int i=0; i +Date: Mon, 16 Dec 2013 18:58:12 +0000 +Subject: [PATCH 20/77] CGUIFontTTFBase::RenderCharacter can now append to + arbitrary vectors of vertices rather than only CGUIFontTTFBase::m_vertex + +--- + xbmc/guilib/GUIFontTTF.cpp | 12 +++++++----- + xbmc/guilib/GUIFontTTF.h | 2 +- + 2 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index 0a80471..848c5c8 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -329,6 +329,8 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + { + Begin(); + ++ std::vector &vertices = m_vertex; ++ + // save the origin, which is scaled separately + m_originX = x; + m_originY = y; +@@ -409,7 +411,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + + for (int i = 0; i < 3; i++) + { +- RenderCharacter(startX + cursorX, startY, period, color, !scrolling); ++ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices); + cursorX += period->advance; + } + break; +@@ -418,7 +420,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) + break; // exceeded max allowed width - stop rendering + +- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling); ++ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices); + if ( alignment & XBFONT_JUSTIFIED ) + { + if ((*pos & 0xffff) == L' ') +@@ -675,7 +677,7 @@ bool CGUIFontTTFBase::CacheCharacter(wchar_t letter, uint32_t style, Character * + return true; + } + +-void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX) ++void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector &vertices) + { + // actual image width isn't same as the character width as that is + // just baseline width and height should include the descent +@@ -741,8 +743,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c + float tt = texture.y1 * m_textureScaleY; + float tb = texture.y2 * m_textureScaleY; + +- m_vertex.resize(m_vertex.size() + 4); +- SVertex* v = &m_vertex[m_vertex.size() - 4]; ++ vertices.resize(vertices.size() + 4); ++ SVertex* v = &vertices[vertices.size() - 4]; + m_color = color; + + unsigned char r = GET_R(color) +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index 10a7060..dde0350 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -109,7 +109,7 @@ class CGUIFontTTFBase + // Stuff for pre-rendering for speed + inline Character *GetCharacter(character_t letter); + bool CacheCharacter(wchar_t letter, uint32_t style, Character *ch); +- void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX); ++ void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector &vertices); + void ClearCharacterCache(); + + virtual CBaseTexture* ReallocTexture(unsigned int& newHeight) = 0; + +From 4a29d6593f48ecac6b1cee902dccbbfd99bd4348 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 15 Jan 2014 17:18:38 +0000 +Subject: [PATCH 21/77] Add a cache of font glyph bounding box vertices. + +This is implemented as a template because ultimately we will key on different +parameters and store values of different types, depending upon whether we +have a GLES or non-GLES backend, and for GLES, whether or not the currently +applicable transformation matrices permit the use of hardware clipping. +--- + XBMC.xcodeproj/project.pbxproj | 10 ++ + project/VS2010Express/XBMC.vcxproj | 2 + + project/VS2010Express/XBMC.vcxproj.filters | 6 + + xbmc/guilib/GUIFontCache.cpp | 105 ++++++++++++++ + xbmc/guilib/GUIFontCache.h | 217 +++++++++++++++++++++++++++++ + xbmc/guilib/GUIFontTTF.cpp | 181 +++++++++++++----------- + xbmc/guilib/GUIFontTTF.h | 5 + + xbmc/guilib/GUIFontTTFGL.cpp | 1 + + xbmc/guilib/GraphicContext.h | 1 + + xbmc/guilib/Makefile.in | 1 + + xbmc/guilib/TransformMatrix.h | 11 ++ + 11 files changed, 456 insertions(+), 84 deletions(-) + create mode 100644 xbmc/guilib/GUIFontCache.cpp + create mode 100644 xbmc/guilib/GUIFontCache.h + +diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj +index 10a2e89..1eb7173 100644 +--- a/XBMC.xcodeproj/project.pbxproj ++++ b/XBMC.xcodeproj/project.pbxproj +@@ -168,6 +168,9 @@ + 1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D638126161E211E003603ED /* PeripheralImon.cpp */; }; + 1DAFDB7C16DFDCA7007F8C68 /* PeripheralBusCEC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DAFDB7A16DFDCA7007F8C68 /* PeripheralBusCEC.cpp */; }; + 1DE0443515828F4B005DDB4D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; }; ++ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; }; ++ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; }; ++ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2F4564D31970129A00396109 /* GUIFontCache.cpp */; }; + 32C631281423A90F00F18420 /* JpegIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32C631261423A90F00F18420 /* JpegIO.cpp */; }; + 36A9443D15821E2800727135 /* DatabaseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443B15821E2800727135 /* DatabaseUtils.cpp */; }; + 36A9444115821E7C00727135 /* SortUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443F15821E7C00727135 /* SortUtils.cpp */; }; +@@ -4008,6 +4011,8 @@ + 1DAFDB7B16DFDCA7007F8C68 /* PeripheralBusCEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeripheralBusCEC.h; sourceTree = ""; }; + 1DE0443315828F4B005DDB4D /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exception.cpp; path = commons/Exception.cpp; sourceTree = ""; }; + 1DE0443415828F4B005DDB4D /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = commons/Exception.h; sourceTree = ""; }; ++ 2F4564D31970129A00396109 /* GUIFontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIFontCache.cpp; sourceTree = ""; }; ++ 2F4564D41970129A00396109 /* GUIFontCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIFontCache.h; sourceTree = ""; }; + 32C631261423A90F00F18420 /* JpegIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JpegIO.cpp; sourceTree = ""; }; + 32C631271423A90F00F18420 /* JpegIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JpegIO.h; sourceTree = ""; }; + 36A9443B15821E2800727135 /* DatabaseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseUtils.cpp; sourceTree = ""; }; +@@ -6513,6 +6518,8 @@ + 18B7C7101294222D009E7A26 /* GUIFixedListContainer.h */, + 18B7C76B1294222E009E7A26 /* GUIFont.cpp */, + 18B7C7111294222D009E7A26 /* GUIFont.h */, ++ 2F4564D31970129A00396109 /* GUIFontCache.cpp */, ++ 2F4564D41970129A00396109 /* GUIFontCache.h */, + 18B7C76C1294222E009E7A26 /* GUIFontManager.cpp */, + 18B7C7121294222D009E7A26 /* GUIFontManager.h */, + 18B7C76D1294222E009E7A26 /* GUIFontTTF.cpp */, +@@ -11000,6 +11007,7 @@ + 7C5608C70F1754930056433A /* ExternalPlayer.cpp in Sources */, + F584E12E0F257C5100DB26A5 /* HTTPDirectory.cpp in Sources */, + F54C51D20F1E783200D46E3C /* GUIDialogKaraokeSongSelector.cpp in Sources */, ++ 2F4564D51970129A00396109 /* GUIFontCache.cpp in Sources */, + F54C51D50F1E784800D46E3C /* karaokelyricscdg.cpp in Sources */, + F54C51D80F1E785700D46E3C /* karaokelyrics.cpp in Sources */, + F54C51E50F1E787700D46E3C /* karaokelyricstextkar.cpp in Sources */, +@@ -12666,6 +12674,7 @@ + DFF0F45B17528350002DA3A4 /* Control.cpp in Sources */, + DFF0F45C17528350002DA3A4 /* Dialog.cpp in Sources */, + DFF0F45D17528350002DA3A4 /* File.cpp in Sources */, ++ 2F4564D71970129A00396109 /* GUIFontCache.cpp in Sources */, + DFF0F45E17528350002DA3A4 /* InfoTagMusic.cpp in Sources */, + DFF0F45F17528350002DA3A4 /* InfoTagVideo.cpp in Sources */, + DFF0F46017528350002DA3A4 /* Keyboard.cpp in Sources */, +@@ -13465,6 +13474,7 @@ + E499131D174E5DAD00741B6D /* GUIVisualisationControl.cpp in Sources */, + E499131E174E5DAD00741B6D /* GUIWindow.cpp in Sources */, + E499131F174E5DAD00741B6D /* GUIWindowManager.cpp in Sources */, ++ 2F4564D61970129A00396109 /* GUIFontCache.cpp in Sources */, + E4991320174E5DAD00741B6D /* GUIWrappingListContainer.cpp in Sources */, + E4991321174E5DAD00741B6D /* imagefactory.cpp in Sources */, + E4991322174E5DAD00741B6D /* IWindowManagerCallback.cpp in Sources */, +diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj +index 8e1e4df..a8f3426 100644 +--- a/project/VS2010Express/XBMC.vcxproj ++++ b/project/VS2010Express/XBMC.vcxproj +@@ -425,6 +425,7 @@ + + + ++ + + + +@@ -1744,6 +1745,7 @@ + + + ++ + + + +diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters +index fcec4f0..e8ac96e 100644 +--- a/project/VS2010Express/XBMC.vcxproj.filters ++++ b/project/VS2010Express/XBMC.vcxproj.filters +@@ -991,6 +991,9 @@ + + guilib + ++ ++ guilib ++ + + guilib + +@@ -3882,6 +3885,9 @@ + + guilib + ++ ++ guilib ++ + + guilib + +diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp +new file mode 100644 +index 0000000..2c72f9c +--- /dev/null ++++ b/xbmc/guilib/GUIFontCache.cpp +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2005-2013 Team XBMC ++ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include ++#include ++#include "utils/StdString.h" // required by GUIFontTTF.h ++#include "GUIFontTTF.h" ++#include "GraphicContext.h" ++ ++template ++void CGUIFontCacheEntry::Reassign::operator()(CGUIFontCacheEntry &entry) ++{ ++ entry.m_key.m_pos = m_key.m_pos; ++ entry.m_key.m_colors.assign(m_key.m_colors.begin(), m_key.m_colors.end()); ++ entry.m_key.m_text.assign(m_key.m_text.begin(), m_key.m_text.end()); ++ entry.m_key.m_alignment = m_key.m_alignment; ++ entry.m_key.m_maxPixelWidth = m_key.m_maxPixelWidth; ++ entry.m_key.m_scrolling = m_key.m_scrolling; ++ entry.m_matrix = m_key.m_matrix; ++ entry.m_key.m_scaleX = m_key.m_scaleX; ++ entry.m_key.m_scaleY = m_key.m_scaleY; ++ ++ entry.m_lastUsedMillis = m_nowMillis; ++ entry.m_value.clear(); ++} ++ ++template ++CGUIFontCacheEntry::~CGUIFontCacheEntry() ++{ ++ delete &m_key.m_colors; ++ delete &m_key.m_text; ++ m_value.clear(); ++} ++ ++template ++Value &CGUIFontCache::Lookup(Position &pos, ++ const vecColors &colors, const vecText &text, ++ uint32_t alignment, float maxPixelWidth, ++ bool scrolling, ++ unsigned int nowMillis, bool &dirtyCache) ++{ ++ const CGUIFontCacheKey key(pos, ++ const_cast(colors), const_cast(text), ++ alignment, maxPixelWidth, ++ scrolling, g_graphicsContext.GetGUIMatrix(), ++ g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY()); ++ EntryHashIterator i = m_list.template get().find(key); ++ if (i == m_list.template get().end()) ++ { ++ /* Cache miss */ ++ EntryAgeIterator oldest = m_list.template get().begin(); ++ if (!m_list.template get().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT) ++ { ++ /* The oldest existing entry is old enough to expire and reuse */ ++ m_list.template get().modify(m_list.template project(oldest), typename CGUIFontCacheEntry::Reassign(key, nowMillis)); ++ m_list.template get().relocate(m_list.template get().end(), oldest); ++ } ++ else ++ { ++ /* We need a new entry instead */ ++ /* Yes, this causes the creation an destruction of a temporary entry, but ++ * this code ought to only be used infrequently, when the cache needs to grow */ ++ m_list.template get().push_back(CGUIFontCacheEntry(*this, key, nowMillis)); ++ } ++ dirtyCache = true; ++ return (--m_list.template get().end())->m_value; ++ } ++ else ++ { ++ /* Cache hit */ ++ /* Update time in entry and move to the back of the list */ ++ i->m_lastUsedMillis = nowMillis; ++ m_list.template get().relocate(m_list.template get().end(), m_list.template project(i)); ++ dirtyCache = false; ++ return i->m_value; ++ } ++} ++ ++template ++void CGUIFontCache::Flush() ++{ ++ m_list.template get().clear(); ++} ++ ++template void CGUIFontCacheEntry::Reassign::operator()(CGUIFontCacheEntry &entry); ++template CGUIFontCacheEntry::~CGUIFontCacheEntry(); ++template CGUIFontCacheStaticValue &CGUIFontCache::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); ++template void CGUIFontCache::Flush(); +diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h +new file mode 100644 +index 0000000..ef65845 +--- /dev/null ++++ b/xbmc/guilib/GUIFontCache.h +@@ -0,0 +1,217 @@ ++/*! ++\file GUIFontCache.h ++\brief ++*/ ++ ++#ifndef CGUILIB_GUIFONTCACHE_H ++#define CGUILIB_GUIFONTCACHE_H ++#pragma once ++ ++/* ++ * Copyright (C) 2005-2013 Team XBMC ++ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "boost/multi_index_container.hpp" ++#include "boost/multi_index/sequenced_index.hpp" ++#include "boost/multi_index/hashed_index.hpp" ++#include "boost/multi_index/member.hpp" ++ ++#include "TransformMatrix.h" ++ ++using namespace boost::multi_index; ++ ++#define FONT_CACHE_TIME_LIMIT (1000) ++ ++template class CGUIFontCache; ++class CGUIFontTTFBase; ++ ++template ++struct CGUIFontCacheKey ++{ ++ Position m_pos; ++ vecColors &m_colors; ++ vecText &m_text; ++ uint32_t m_alignment; ++ float m_maxPixelWidth; ++ bool m_scrolling; ++ const TransformMatrix &m_matrix; ++ float m_scaleX; ++ float m_scaleY; ++ ++ CGUIFontCacheKey(Position pos, ++ vecColors &colors, vecText &text, ++ uint32_t alignment, float maxPixelWidth, ++ bool scrolling, const TransformMatrix &matrix, ++ float scaleX, float scaleY) : ++ m_pos(pos), ++ m_colors(colors), m_text(text), ++ m_alignment(alignment), m_maxPixelWidth(maxPixelWidth), ++ m_scrolling(scrolling), m_matrix(matrix), ++ m_scaleX(scaleX), m_scaleY(scaleY) ++ {} ++}; ++ ++template ++struct CGUIFontCacheEntry ++{ ++ const CGUIFontCache &m_cache; ++ CGUIFontCacheKey m_key; ++ TransformMatrix m_matrix; ++ ++ /* These need to be declared as mutable to get round the fact that only ++ * const iterators are available. These fields do not affect comparison or ++ * hash functors, so from the container's point of view, they are mutable. */ ++ mutable unsigned int m_lastUsedMillis; ++ mutable Value m_value; ++ ++ CGUIFontCacheEntry(const CGUIFontCache &cache, const CGUIFontCacheKey &key, unsigned int nowMillis) : ++ m_cache(cache), ++ m_key(key.m_pos, ++ *new vecColors, *new vecText, ++ key.m_alignment, key.m_maxPixelWidth, ++ key.m_scrolling, m_matrix, ++ key.m_scaleX, key.m_scaleY), ++ m_lastUsedMillis(nowMillis) ++ { ++ m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end()); ++ m_key.m_text.assign(key.m_text.begin(), key.m_text.end()); ++ m_matrix = key.m_matrix; ++ } ++ ++ CGUIFontCacheEntry(const CGUIFontCacheEntry &other) : ++ m_cache(other.m_cache), ++ m_key(other.m_key.m_pos, ++ *new vecColors, *new vecText, ++ other.m_key.m_alignment, other.m_key.m_maxPixelWidth, ++ other.m_key.m_scrolling, m_matrix, ++ other.m_key.m_scaleX, other.m_key.m_scaleY), ++ m_lastUsedMillis(other.m_lastUsedMillis), ++ m_value(other.m_value) ++ { ++ m_key.m_colors.assign(other.m_key.m_colors.begin(), other.m_key.m_colors.end()); ++ m_key.m_text.assign(other.m_key.m_text.begin(), other.m_key.m_text.end()); ++ m_matrix = other.m_key.m_matrix; ++ } ++ ++ struct Reassign ++ { ++ Reassign(const CGUIFontCacheKey &key, unsigned int nowMillis) : m_key(key), m_nowMillis(nowMillis) {} ++ void operator()(CGUIFontCacheEntry &entry); ++ private: ++ const CGUIFontCacheKey &m_key; ++ unsigned int m_nowMillis; ++ }; ++ ++ ~CGUIFontCacheEntry(); ++}; ++ ++template ++struct CGUIFontCacheHash ++{ ++ size_t operator()(const CGUIFontCacheKey &key) const ++ { ++ /* Not much effort has gone into choosing this hash function */ ++ size_t hash = 0, i; ++ for (i = 0; i < 3 && i < key.m_text.size(); ++i) ++ hash += key.m_text[i]; ++ if (key.m_colors.size()) ++ hash += key.m_colors[0]; ++ hash += MatrixHashContribution(key); ++ return hash; ++ } ++}; ++ ++template ++struct CGUIFontCacheKeysMatch ++{ ++ bool operator()(const CGUIFontCacheKey &a, const CGUIFontCacheKey &b) const ++ { ++ return a.m_text == b.m_text && ++ a.m_colors == b.m_colors && ++ a.m_alignment == b.m_alignment && ++ a.m_scrolling == b.m_scrolling && ++ a.m_maxPixelWidth == b.m_maxPixelWidth && ++ Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) && ++ a.m_scaleX == b.m_scaleX && ++ a.m_scaleY == b.m_scaleY; ++ } ++}; ++ ++template ++class CGUIFontCache ++{ ++ /* Empty structs used as tags to identify indexes */ ++ struct Age {}; ++ struct Hash {}; ++ ++ typedef multi_index_container< ++ CGUIFontCacheEntry, ++ indexed_by< ++ sequenced >, ++ hashed_unique, member, CGUIFontCacheKey, &CGUIFontCacheEntry::m_key>, CGUIFontCacheHash, CGUIFontCacheKeysMatch > ++ > ++ > EntryList; ++ ++ typedef typename EntryList::template index::type::iterator EntryAgeIterator; ++ typedef typename EntryList::template index::type::iterator EntryHashIterator; ++ ++ EntryList m_list; ++ ++public: ++ const CGUIFontTTFBase &m_font; ++ ++ CGUIFontCache(CGUIFontTTFBase &font) : m_font(font) {} ++ Value &Lookup(Position &pos, ++ const vecColors &colors, const vecText &text, ++ uint32_t alignment, float maxPixelWidth, ++ bool scrolling, ++ unsigned int nowMillis, bool &dirtyCache); ++ void Flush(); ++}; ++ ++struct CGUIFontCacheStaticPosition ++{ ++ float m_x; ++ float m_y; ++ CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {} ++}; ++ ++typedef std::vector CGUIFontCacheStaticValue; ++ ++inline bool Match(const CGUIFontCacheStaticPosition &a, const TransformMatrix &a_m, ++ const CGUIFontCacheStaticPosition &b, const TransformMatrix &b_m, ++ bool scrolling) ++{ ++ return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m; ++} ++ ++inline float MatrixHashContribution(const CGUIFontCacheKey &a) ++{ ++ /* Ensure horizontally translated versions end up in different buckets */ ++ return a.m_matrix.m[0][3]; ++} ++ ++#endif +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index 848c5c8..0290fc4 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -27,6 +27,7 @@ + #include "utils/MathUtils.h" + #include "utils/log.h" + #include "windowing/WindowingFactory.h" ++#include "threads/SystemClock.h" + + #include + +@@ -131,7 +132,7 @@ class CFreeTypeLibrary + XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library + #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary) + +-CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) ++CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this) + { + m_texture = NULL; + m_char = NULL; +@@ -329,108 +330,120 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + { + Begin(); + +- std::vector &vertices = m_vertex; +- +- // save the origin, which is scaled separately +- m_originX = x; +- m_originY = y; +- +- // Check if we will really need to truncate or justify the text +- if ( alignment & XBFONT_TRUNCATED ) ++ bool dirtyCache; ++ CGUIFontCacheStaticPosition staticPos(x, y); ++ std::vector &vertices = m_staticCache.Lookup(staticPos, ++ colors, text, ++ alignment, maxPixelWidth, ++ scrolling, ++ XbmcThreads::SystemClockMillis(), ++ dirtyCache); ++ if (dirtyCache) + { +- if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth) +- alignment &= ~XBFONT_TRUNCATED; +- } +- else if ( alignment & XBFONT_JUSTIFIED ) +- { +- if ( maxPixelWidth <= 0.0f ) +- alignment &= ~XBFONT_JUSTIFIED; +- } ++ // save the origin, which is scaled separately ++ m_originX = x; ++ m_originY = y; + +- // calculate sizing information +- float startX = 0; +- float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering ++ // Check if we will really need to truncate or justify the text ++ if ( alignment & XBFONT_TRUNCATED ) ++ { ++ if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth) ++ alignment &= ~XBFONT_TRUNCATED; ++ } ++ else if ( alignment & XBFONT_JUSTIFIED ) ++ { ++ if ( maxPixelWidth <= 0.0f ) ++ alignment &= ~XBFONT_JUSTIFIED; ++ } + +- if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) ) +- { +- // Get the extent of this line +- float w = GetTextWidthInternal( text.begin(), text.end() ); ++ // calculate sizing information ++ float startX = 0; ++ float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0; // vertical centering + +- if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues +- w = maxPixelWidth; ++ if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) ) ++ { ++ // Get the extent of this line ++ float w = GetTextWidthInternal( text.begin(), text.end() ); + +- if ( alignment & XBFONT_CENTER_X) +- w *= 0.5f; +- // Offset this line's starting position +- startX -= w; +- } ++ if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues ++ w = maxPixelWidth; + +- float spacePerLetter = 0; // for justification effects +- if ( alignment & XBFONT_JUSTIFIED ) +- { +- // first compute the size of the text to render in both characters and pixels +- unsigned int lineChars = 0; +- float linePixels = 0; +- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) ++ if ( alignment & XBFONT_CENTER_X) ++ w *= 0.5f; ++ // Offset this line's starting position ++ startX -= w; ++ } ++ ++ float spacePerLetter = 0; // for justification effects ++ if ( alignment & XBFONT_JUSTIFIED ) + { +- Character *ch = GetCharacter(*pos); +- if (ch) +- { // spaces have multiple times the justification spacing of normal letters +- lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1; +- linePixels += ch->advance; ++ // first compute the size of the text to render in both characters and pixels ++ unsigned int lineChars = 0; ++ float linePixels = 0; ++ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) ++ { ++ Character *ch = GetCharacter(*pos); ++ if (ch) ++ { // spaces have multiple times the justification spacing of normal letters ++ lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1; ++ linePixels += ch->advance; ++ } + } ++ if (lineChars > 1) ++ spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1); + } +- if (lineChars > 1) +- spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1); +- } +- float cursorX = 0; // current position along the line +- +- for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) +- { +- // If starting text on a new line, determine justification effects +- // Get the current letter in the CStdString +- color_t color = (*pos & 0xff0000) >> 16; +- if (color >= colors.size()) +- color = 0; +- color = colors[color]; ++ float cursorX = 0; // current position along the line + +- // grab the next character +- Character *ch = GetCharacter(*pos); +- if (!ch) continue; +- +- if ( alignment & XBFONT_TRUNCATED ) ++ for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos) + { +- // Check if we will be exceeded the max allowed width +- if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth ) +- { +- // Yup. Let's draw the ellipses, then bail +- // Perhaps we should really bail to the next line in this case?? +- Character *period = GetCharacter(L'.'); +- if (!period) +- break; ++ // If starting text on a new line, determine justification effects ++ // Get the current letter in the CStdString ++ color_t color = (*pos & 0xff0000) >> 16; ++ if (color >= colors.size()) ++ color = 0; ++ color = colors[color]; ++ ++ // grab the next character ++ Character *ch = GetCharacter(*pos); ++ if (!ch) continue; + +- for (int i = 0; i < 3; i++) ++ if ( alignment & XBFONT_TRUNCATED ) ++ { ++ // Check if we will be exceeded the max allowed width ++ if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth ) + { +- RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices); +- cursorX += period->advance; ++ // Yup. Let's draw the ellipses, then bail ++ // Perhaps we should really bail to the next line in this case?? ++ Character *period = GetCharacter(L'.'); ++ if (!period) ++ break; ++ ++ for (int i = 0; i < 3; i++) ++ { ++ RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices); ++ cursorX += period->advance; ++ } ++ break; + } +- break; + } +- } +- else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) +- break; // exceeded max allowed width - stop rendering ++ else if (maxPixelWidth > 0 && cursorX > maxPixelWidth) ++ break; // exceeded max allowed width - stop rendering + +- RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices); +- if ( alignment & XBFONT_JUSTIFIED ) +- { +- if ((*pos & 0xffff) == L' ') +- cursorX += ch->advance + spacePerLetter * justification_word_weight; ++ RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices); ++ if ( alignment & XBFONT_JUSTIFIED ) ++ { ++ if ((*pos & 0xffff) == L' ') ++ cursorX += ch->advance + spacePerLetter * justification_word_weight; ++ else ++ cursorX += ch->advance + spacePerLetter; ++ } + else +- cursorX += ch->advance + spacePerLetter; ++ cursorX += ch->advance; + } +- else +- cursorX += ch->advance; + } ++ /* Append the new vertices (from the cache or otherwise) to the set collected ++ * since the first Begin() call */ ++ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); + + End(); + } +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index dde0350..77111bc 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -64,6 +64,9 @@ struct SVertex + }; + + ++#include "GUIFontCache.h" ++ ++ + class CGUIFontTTFBase + { + friend class CGUIFont; +@@ -165,6 +168,8 @@ class CGUIFontTTFBase + + CStdString m_strFileName; + ++ CGUIFontCache m_staticCache; ++ + private: + virtual bool FirstBegin() = 0; + virtual void LastEnd() = 0; +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index b76c6a5..9935ea4 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -221,6 +221,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) + m_textureScaleX = 1.0f / m_textureWidth; + if (m_textureHeight < newHeight) + CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight); ++ m_staticCache.Flush(); + + memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch()); + if (m_texture) +diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h +index 6c2dcd4..bab2457 100644 +--- a/xbmc/guilib/GraphicContext.h ++++ b/xbmc/guilib/GraphicContext.h +@@ -146,6 +146,7 @@ class CGraphicContext : public CCriticalSection, + inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.matrix.TransformPosition(x, y, z); } + bool RectIsAngled(float x1, float y1, float x2, float y2) const; + ++ inline const TransformMatrix &GetGUIMatrix() const XBMC_FORCE_INLINE { return m_finalTransform.matrix; } + inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_finalTransform.scaleX; } + inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_finalTransform.scaleY; } + inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE +diff --git a/xbmc/guilib/Makefile.in b/xbmc/guilib/Makefile.in +index 086fb0d..af82979 100644 +--- a/xbmc/guilib/Makefile.in ++++ b/xbmc/guilib/Makefile.in +@@ -23,6 +23,7 @@ SRCS += GUIEditControl.cpp + SRCS += GUIFadeLabelControl.cpp + SRCS += GUIFixedListContainer.cpp + SRCS += GUIFont.cpp ++SRCS += GUIFontCache.cpp + SRCS += GUIFontManager.cpp + SRCS += GUIFontTTF.cpp + SRCS += GUIImage.cpp +diff --git a/xbmc/guilib/TransformMatrix.h b/xbmc/guilib/TransformMatrix.h +index f351c99..9036ba9 100644 +--- a/xbmc/guilib/TransformMatrix.h ++++ b/xbmc/guilib/TransformMatrix.h +@@ -245,3 +245,14 @@ class TransformMatrix + float alpha; + bool identity; + }; ++ ++inline bool operator==(const TransformMatrix &a, const TransformMatrix &b) ++{ ++ return a.alpha == b.alpha && ((a.identity && b.identity) || ++ (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof a.m / sizeof a.m[0][0], &b.m[0][0]))); ++} ++ ++inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b) ++{ ++ return !operator==(a, b); ++} + +From 7a0a7b745d08f94b93ab789b33aa9447e9427e29 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Thu, 23 Jan 2014 22:24:17 +0000 +Subject: [PATCH 22/77] Lay the groundwork for hardware clipping. + +For glScissor() to replace CGraphicContext::ClipRect, a necessary condition +is that no shear or rotation is introduced between the coordinate systems +they use; this depends upon the settings of the GUI matrix m_finalTransform +as well as the OpenGL model-view and projection matrices. These all remain +unchanged between paired calls of CGUIShader::OnEnabled and +CGUIShader::OnDisabled, so we scan the matrices in CGUIShader::OnEnabled to +see whether hardware clipping is possible. + +Then, in CGUIFontTTFBase::RenderCharacter, we don't apply software clipping +in such cases. However, because vertices arising from multiple +CGUIFontTTFBase::DrawTextInternal calls (each of which often uses a different +clip rectangle) get lumped into the same vector, which only at the end is +passed to OpenGL for rendering, we need to wait a few commits before we can +actually apply hardware clipping. In the meantime, expect to see rendering +errors. +--- + xbmc/guilib/GUIFontTTF.cpp | 3 +- + xbmc/guilib/GUIShader.cpp | 80 +++++++++++++++++++++++++++++++- + xbmc/guilib/GUIShader.h | 11 +++++ + xbmc/guilib/GraphicContext.cpp | 10 ++++ + xbmc/guilib/GraphicContext.h | 1 + + xbmc/rendering/RenderSystem.h | 2 + + xbmc/rendering/gles/RenderSystemGLES.cpp | 22 +++++++++ + xbmc/rendering/gles/RenderSystemGLES.h | 2 + + 8 files changed, 128 insertions(+), 3 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index 0290fc4..e3808d9 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -709,7 +709,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c + (posY + ch->offsetY + height) * g_graphicsContext.GetGUIScaleY()); + vertex += CPoint(m_originX, m_originY); + CRect texture(ch->left, ch->top, ch->right, ch->bottom); +- g_graphicsContext.ClipRect(vertex, texture); ++ if (!g_Windowing.ScissorsCanEffectClipping()) ++ g_graphicsContext.ClipRect(vertex, texture); + + // transform our positions - note, no scaling due to GUI calibration/resolution occurs + float x[4], y[4], z[4]; +diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp +index 23cb84f..5d836cee 100644 +--- a/xbmc/guilib/GUIShader.cpp ++++ b/xbmc/guilib/GUIShader.cpp +@@ -26,6 +26,8 @@ + #include "GUIShader.h" + #include "MatrixGLES.h" + #include "utils/log.h" ++#include "windowing/WindowingFactory.h" ++#include "guilib/GraphicContext.h" + + using namespace Shaders; + +@@ -88,8 +90,82 @@ bool CGUIShader::OnEnabled() + { + // This is called after glUseProgram() + +- glUniformMatrix4fv(m_hProj, 1, GL_FALSE, g_matrices.GetMatrix(MM_PROJECTION)); +- glUniformMatrix4fv(m_hModel, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); ++ GLfloat *projMatrix = g_matrices.GetMatrix(MM_PROJECTION); ++ GLfloat *modelMatrix = g_matrices.GetMatrix(MM_MODELVIEW); ++ glUniformMatrix4fv(m_hProj, 1, GL_FALSE, projMatrix); ++ glUniformMatrix4fv(m_hModel, 1, GL_FALSE, modelMatrix); ++ ++ const TransformMatrix &guiMatrix = g_graphicsContext.GetGUIMatrix(); ++ CRect viewPort; // absolute positions of corners ++ g_Windowing.GetViewPort(viewPort); ++ ++ /* glScissor operates in window coordinates. In order that we can use it to ++ * perform clipping, we must ensure that there is an independent linear ++ * transformation from the coordinate system used by CGraphicContext::ClipRect ++ * to window coordinates, separately for X and Y (in other words, no ++ * rotation or shear is introduced at any stage). To do, this, we need to ++ * check that zeros are present in the following locations: ++ * ++ * GUI matrix: ++ * / * 0 * * \ ++ * | 0 * * * | ++ * \ 0 0 * * / ++ * ^ TransformMatrix::TransformX/Y/ZCoord are only ever called with ++ * input z = 0, so this column doesn't matter ++ * Model-view matrix: ++ * / * 0 0 * \ ++ * | 0 * 0 * | ++ * | 0 0 * * | ++ * \ * * * * / <- eye w has no influence on window x/y (last column below ++ * is either 0 or ignored) ++ * Projection matrix: ++ * / * 0 0 0 \ ++ * | 0 * 0 0 | ++ * | * * * * | <- normalised device coordinate z has no influence on window x/y ++ * \ 0 0 * 0 / ++ * ++ * Some of these zeros are not strictly required to ensure this, but they tend ++ * to be zeroed in the common case, so by checking for zeros here, we simplify ++ * the calculation of the window x/y coordinates further down the line. ++ * ++ * (Minor detail: we don't quite deal in window coordinates as defined by ++ * OpenGL, because CRenderSystemGLES::SetScissors flips the Y axis. But all ++ * that's needed to handle that is an effective negation at the stage where ++ * Y is in normalised device coordinates.) ++ */ ++ m_clipPossible = guiMatrix.m[0][1] == 0 && ++ guiMatrix.m[1][0] == 0 && ++ guiMatrix.m[2][0] == 0 && ++ guiMatrix.m[2][1] == 0 && ++ modelMatrix[0+1*4] == 0 && ++ modelMatrix[0+2*4] == 0 && ++ modelMatrix[1+0*4] == 0 && ++ modelMatrix[1+2*4] == 0 && ++ modelMatrix[2+0*4] == 0 && ++ modelMatrix[2+1*4] == 0 && ++ projMatrix[0+1*4] == 0 && ++ projMatrix[0+2*4] == 0 && ++ projMatrix[0+3*4] == 0 && ++ projMatrix[1+0*4] == 0 && ++ projMatrix[1+2*4] == 0 && ++ projMatrix[1+3*4] == 0 && ++ projMatrix[3+0*4] == 0 && ++ projMatrix[3+1*4] == 0 && ++ projMatrix[3+3*4] == 0; ++ if (m_clipPossible) ++ { ++ m_clipXFactor = guiMatrix.m[0][0] * modelMatrix[0+0*4] * projMatrix[0+0*4]; ++ m_clipXOffset = (guiMatrix.m[0][3] * modelMatrix[0+0*4] + modelMatrix[0+3*4]) * projMatrix[0+0*4]; ++ m_clipYFactor = guiMatrix.m[1][1] * modelMatrix[1+1*4] * projMatrix[1+1*4]; ++ m_clipYOffset = (guiMatrix.m[1][3] * modelMatrix[1+1*4] + modelMatrix[1+3*4]) * projMatrix[1+1*4]; ++ float clipW = (guiMatrix.m[2][3] * modelMatrix[2+2*4] + modelMatrix[2+3*4]) * projMatrix[3+2*4]; ++ float xMult = (viewPort.x2 - viewPort.x1) / (2 * clipW); ++ float yMult = (viewPort.y1 - viewPort.y2) / (2 * clipW); // correct for inverted window coordinate scheme ++ m_clipXFactor = m_clipXFactor * xMult; ++ m_clipXOffset = m_clipXOffset * xMult + (viewPort.x2 + viewPort.x1) / 2; ++ m_clipYFactor = m_clipYFactor * yMult; ++ m_clipYOffset = m_clipYOffset * yMult + (viewPort.y2 + viewPort.y1) / 2; ++ } + + return true; + } +diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h +index f7b5d9a..fdf7452 100644 +--- a/xbmc/guilib/GUIShader.h ++++ b/xbmc/guilib/GUIShader.h +@@ -39,6 +39,11 @@ class CGUIShader : public Shaders::CGLSLShaderProgram + GLint GetCord1Loc() { return m_hCord1; } + GLint GetUniColLoc() { return m_hUniCol; } + GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; } ++ bool HardwareClipIsPossible() { return m_clipPossible; } ++ GLfloat GetClipXFactor() { return m_clipXFactor; } ++ GLfloat GetClipXOffset() { return m_clipXOffset; } ++ GLfloat GetClipYFactor() { return m_clipYFactor; } ++ GLfloat GetClipYOffset() { return m_clipYOffset; } + + protected: + GLint m_hTex0; +@@ -54,6 +59,12 @@ class CGUIShader : public Shaders::CGLSLShaderProgram + + GLfloat *m_proj; + GLfloat *m_model; ++ ++ bool m_clipPossible; ++ GLfloat m_clipXFactor; ++ GLfloat m_clipXOffset; ++ GLfloat m_clipYFactor; ++ GLfloat m_clipYOffset; + }; + + #endif // GUI_SHADER_H +diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp +index 38f17a7..5bffdf5 100644 +--- a/xbmc/guilib/GraphicContext.cpp ++++ b/xbmc/guilib/GraphicContext.cpp +@@ -167,6 +167,16 @@ void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2) + } + } + ++CRect CGraphicContext::GetClipRegion() ++{ ++ if (m_clipRegions.empty()) ++ return CRect(0, 0, m_iScreenWidth, m_iScreenHeight); ++ CRect clipRegion(m_clipRegions.top()); ++ if (!m_origins.empty()) ++ clipRegion -= m_origins.top(); ++ return clipRegion; ++} ++ + bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */) + { + // transform coordinates - we may have a rotation which changes the positioning of the +diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h +index bab2457..0a27643 100644 +--- a/xbmc/guilib/GraphicContext.h ++++ b/xbmc/guilib/GraphicContext.h +@@ -199,6 +199,7 @@ class CGraphicContext : public CCriticalSection, + void ApplyHardwareTransform(); + void RestoreHardwareTransform(); + void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL); ++ CRect GetClipRegion(); + inline void AddGUITransform() + { + m_transforms.push(m_finalTransform); +diff --git a/xbmc/rendering/RenderSystem.h b/xbmc/rendering/RenderSystem.h +index fa64eba..c1dfb93 100644 +--- a/xbmc/rendering/RenderSystem.h ++++ b/xbmc/rendering/RenderSystem.h +@@ -110,6 +110,8 @@ class CRenderSystemBase + virtual void GetViewPort(CRect& viewPort) = 0; + virtual void RestoreViewPort() {}; + ++ virtual bool ScissorsCanEffectClipping() { return false; } ++ virtual CRect ClipRectToScissorRect(const CRect &rect) { return CRect(); } + virtual void SetScissors(const CRect &rect) = 0; + virtual void ResetScissors() = 0; + +diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp +index 653c9ec..deb3afc 100644 +--- a/xbmc/rendering/gles/RenderSystemGLES.cpp ++++ b/xbmc/rendering/gles/RenderSystemGLES.cpp +@@ -533,6 +533,28 @@ void CRenderSystemGLES::SetViewPort(CRect& viewPort) + m_viewPort[3] = viewPort.Height(); + } + ++bool CRenderSystemGLES::ScissorsCanEffectClipping() ++{ ++ if (m_pGUIshader[m_method]) ++ return m_pGUIshader[m_method]->HardwareClipIsPossible(); ++ ++ return false; ++} ++ ++CRect CRenderSystemGLES::ClipRectToScissorRect(const CRect &rect) ++{ ++ if (!m_pGUIshader[m_method]) ++ return CRect(); ++ float xFactor = m_pGUIshader[m_method]->GetClipXFactor(); ++ float xOffset = m_pGUIshader[m_method]->GetClipXOffset(); ++ float yFactor = m_pGUIshader[m_method]->GetClipYFactor(); ++ float yOffset = m_pGUIshader[m_method]->GetClipYOffset(); ++ return CRect(rect.x1 * xFactor + xOffset, ++ rect.y1 * yFactor + yOffset, ++ rect.x2 * xFactor + xOffset, ++ rect.y2 * yFactor + yOffset); ++} ++ + void CRenderSystemGLES::SetScissors(const CRect &rect) + { + if (!m_bRenderCreated) +diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h +index 98e398a..81ee49e 100644 +--- a/xbmc/rendering/gles/RenderSystemGLES.h ++++ b/xbmc/rendering/gles/RenderSystemGLES.h +@@ -63,6 +63,8 @@ class CRenderSystemGLES : public CRenderSystemBase + virtual void SetViewPort(CRect& viewPort); + virtual void GetViewPort(CRect& viewPort); + ++ virtual bool ScissorsCanEffectClipping(); ++ virtual CRect ClipRectToScissorRect(const CRect &rect); + virtual void SetScissors(const CRect& rect); + virtual void ResetScissors(); + + +From a5604966904a4e2fc856bd7c34175a71ca530dfe Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Thu, 23 Jan 2014 16:42:22 +0000 +Subject: [PATCH 23/77] Increase font cache hit rate by keying on the + fractional part of m_originX and m_originY *after* they have been through the + graphics context's transformation matrix, plus the scale/rotation elements of + the matrix, rather than the origin in the original frame of reference plus + the complete transformation matrix. All vertices of individual glyph bounding + boxes are a constant offset from this position, and when the fractional part + of the translation is a match, the rounding of each vertex will be in the + same direction; this permits us to calculate the desired vertices from the + cached ones simply by adding the integer parts of the translations with no + additional rounding steps. + +Note that this requires that software clipping is *not* performed. +--- + xbmc/guilib/GUIFontCache.cpp | 8 +++++++ + xbmc/guilib/GUIFontCache.h | 43 +++++++++++++++++++++++++++++++++++ + xbmc/guilib/GUIFontTTF.cpp | 53 +++++++++++++++++++++++++++++++++++--------- + xbmc/guilib/GUIFontTTF.h | 1 + + 4 files changed, 95 insertions(+), 10 deletions(-) + +diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp +index 2c72f9c..df466a5 100644 +--- a/xbmc/guilib/GUIFontCache.cpp ++++ b/xbmc/guilib/GUIFontCache.cpp +@@ -85,6 +85,9 @@ Value &CGUIFontCache::Lookup(Position &pos, + else + { + /* Cache hit */ ++ /* Update the translation arguments so that they hold the offset to apply ++ * to the cached values (but only in the dynamic case) */ ++ pos.UpdateWithOffsets(i->m_key.m_pos, scrolling); + /* Update time in entry and move to the back of the list */ + i->m_lastUsedMillis = nowMillis; + m_list.template get().relocate(m_list.template get().end(), m_list.template project(i)); +@@ -103,3 +106,8 @@ template void CGUIFontCacheEntry::~CGUIFontCacheEntry(); + template CGUIFontCacheStaticValue &CGUIFontCache::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); + template void CGUIFontCache::Flush(); ++ ++template void CGUIFontCacheEntry::Reassign::operator()(CGUIFontCacheEntry &entry); ++template CGUIFontCacheEntry::~CGUIFontCacheEntry(); ++template CGUIFontCacheDynamicValue &CGUIFontCache::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); ++template void CGUIFontCache::Flush(); +diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h +index ef65845..d913dee 100644 +--- a/xbmc/guilib/GUIFontCache.h ++++ b/xbmc/guilib/GUIFontCache.h +@@ -44,6 +44,7 @@ + using namespace boost::multi_index; + + #define FONT_CACHE_TIME_LIMIT (1000) ++#define FONT_CACHE_DIST_LIMIT (0.01) + + template class CGUIFontCache; + class CGUIFontTTFBase; +@@ -197,6 +198,7 @@ struct CGUIFontCacheStaticPosition + float m_x; + float m_y; + CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {} ++ void UpdateWithOffsets(const CGUIFontCacheStaticPosition &cached, bool scrolling) {} + }; + + typedef std::vector CGUIFontCacheStaticValue; +@@ -214,4 +216,45 @@ inline float MatrixHashContribution(const CGUIFontCacheKey CGUIFontCacheDynamicValue; ++ ++inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m, ++ const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m, ++ bool scrolling) ++{ ++ float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT; ++ float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT; ++ float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT; ++ return (scrolling || diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) && ++ diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT && ++ diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT && ++ a_m.m[0][0] == b_m.m[0][0] && ++ a_m.m[1][1] == b_m.m[1][1] && ++ a_m.m[2][2] == b_m.m[2][2]; ++ // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements ++} ++ ++inline float MatrixHashContribution(const CGUIFontCacheKey &a) ++{ ++ return 0; +} + + #endif +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index e3808d9..412f47a 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -132,7 +132,7 @@ class CFreeTypeLibrary + XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library + #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary) + +-CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this) ++CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this), m_dynamicCache(*this) + { + m_texture = NULL; + m_char = NULL; +@@ -331,13 +331,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + Begin(); + + bool dirtyCache; ++ bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping(); + CGUIFontCacheStaticPosition staticPos(x, y); +- std::vector &vertices = m_staticCache.Lookup(staticPos, +- colors, text, +- alignment, maxPixelWidth, +- scrolling, +- XbmcThreads::SystemClockMillis(), +- dirtyCache); ++ CGUIFontCacheDynamicPosition dynamicPos; ++ if (hardwareClipping) ++ { ++ dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y), ++ g_graphicsContext.ScaleFinalYCoord(x, y), ++ g_graphicsContext.ScaleFinalZCoord(x, y)); ++ } ++ std::vector &vertices = hardwareClipping ? ++ m_dynamicCache.Lookup(dynamicPos, ++ colors, text, ++ alignment, maxPixelWidth, ++ scrolling, ++ XbmcThreads::SystemClockMillis(), ++ dirtyCache) : ++ m_staticCache.Lookup(staticPos, ++ colors, text, ++ alignment, maxPixelWidth, ++ scrolling, ++ XbmcThreads::SystemClockMillis(), ++ dirtyCache); + if (dirtyCache) + { + // save the origin, which is scaled separately +@@ -440,10 +455,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + else + cursorX += ch->advance; + } ++ if (hardwareClipping) ++ /* Append the new vertices (which we have just constructed in the cache) ++ * to the set collected since the first Begin() call */ ++ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); ++ } ++ else if (hardwareClipping) ++ { ++ /* Apply the translation offset to the vertices from the cache after ++ * appending them to the set collected since the first Begin() call */ ++ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); ++ SVertex *v; ++ for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++) ++ { ++ v->x += dynamicPos.m_x; ++ v->y += dynamicPos.m_y; ++ v->z += dynamicPos.m_z; ++ } + } +- /* Append the new vertices (from the cache or otherwise) to the set collected +- * since the first Begin() call */ +- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); ++ if (!hardwareClipping) ++ /* Append the new vertices (from the cache or otherwise) to the set collected ++ * since the first Begin() call */ ++ m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); + + End(); + } +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index 77111bc..39bfa52 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -169,6 +169,7 @@ class CGUIFontTTFBase + CStdString m_strFileName; + + CGUIFontCache m_staticCache; ++ CGUIFontCache m_dynamicCache; + + private: + virtual bool FirstBegin() = 0; + +From 37f4f936fe6d927b8c556a46d812cebbbe5475d7 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 8 Jan 2014 12:16:33 +0000 +Subject: [PATCH 24/77] Rewrite of scrolling text code. + +No longer shuffles the string round to minimise the number of characters +before the clipping rectangle; this doesn't save much on rendering time but +does harm the effectiveness of the cache. Now uses a pixel offset into the +string rather than a character + pixel offset, and plots the entire string +every time (execpt when the wrap point is visible, in which case the entire +string is plotted twice). + +It also makes motion smoother, because (possibly unintentionally) the +previous code preferred to align the scroll offset with character boundaries. +This would lead to uneven changes of position, especially when the width of +the character currently being scrolled off the edge was only slightly more +than an integral multiple of the scroll increment. +--- + xbmc/guilib/GUIFadeLabelControl.cpp | 8 +-- + xbmc/guilib/GUIFont.cpp | 123 +++++++++++++----------------------- + xbmc/guilib/GUIFont.h | 17 ++--- + xbmc/guilib/GUIRSSControl.cpp | 6 +- + xbmc/utils/RssReader.cpp | 2 +- + xbmc/utils/RssReader.h | 2 +- + 6 files changed, 58 insertions(+), 100 deletions(-) + +diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp +index 844f960..5859d9f 100644 +--- a/xbmc/guilib/GUIFadeLabelControl.cpp ++++ b/xbmc/guilib/GUIFadeLabelControl.cpp +@@ -109,18 +109,14 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d + bool moveToNextLabel = false; + if (!m_scrollOut) + { +- vecText text; +- m_textLayout.GetFirstText(text); +- if (m_scrollInfo.characterPos && m_scrollInfo.characterPos < text.size()) +- text.erase(text.begin(), text.begin() + min((int)m_scrollInfo.characterPos - 1, (int)text.size())); +- if (m_label.font->GetTextWidth(text) < m_width) ++ if (m_scrollInfo.pixelPos + m_width > m_scrollInfo.m_textWidth) + { + if (m_fadeAnim.GetProcess() != ANIM_PROCESS_NORMAL) + m_fadeAnim.QueueAnimation(ANIM_PROCESS_NORMAL); + moveToNextLabel = true; + } + } +- else if (m_scrollInfo.characterPos > m_textLayout.GetTextLength()) ++ else if (m_scrollInfo.pixelPos > m_scrollInfo.m_textWidth) + moveToNextLabel = true; + + // apply the fading animation +diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp +index a7ee668..eb8efdb 100644 +--- a/xbmc/guilib/GUIFont.cpp ++++ b/xbmc/guilib/GUIFont.cpp +@@ -36,7 +36,12 @@ CScrollInfo::CScrollInfo(unsigned int wait /* = 50 */, float pos /* = 0 */, + initialWait = wait; + initialPos = pos; + SetSpeed(speed ? speed : defaultSpeed); +- g_charsetConverter.utf8ToW(scrollSuffix, suffix); ++ CStdStringW wsuffix; ++ g_charsetConverter.utf8ToW(scrollSuffix, wsuffix); ++ suffix.clear(); ++ suffix.reserve(wsuffix.size()); ++ for (vecText::size_type i = 0; i < wsuffix.size(); i++) ++ suffix.push_back(wsuffix[i]); + Reset(); + } + +@@ -115,11 +120,12 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo) + { + // draw at our scroll position + // we handle the scrolling as follows: +- // We scroll on a per-pixel basis up until we have scrolled the first character outside +- // of our viewport, whereby we cycle the string around, and reset the scroll position. +- // +- // pixelPos is the amount in pixels to move the string by. +- // characterPos is the amount in characters to rotate the string by. ++ // We scroll on a per-pixel basis (eschewing the use of character indices ++ // which were also in use previously). The complete string, including suffix, ++ // is plotted to achieve the desired effect - normally just the one time, but ++ // if there is a wrap point within the viewport then it will be plotted twice. ++ // If the string is smaller than the viewport, then it may be plotted even ++ // more times than that. + // + if (scrollInfo.waitTime) + { +@@ -135,54 +141,19 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo) + // move along by the appropriate scroll amount + float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX()); + +- if (scrollInfo.pixelSpeed > 0) ++ if (!scrollInfo.m_widthValid) + { +- // we want to move scrollAmount, grab the next character +- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); +- if (scrollInfo.pixelPos + scrollAmount < charWidth) +- scrollInfo.pixelPos += scrollAmount; // within the current character +- else +- { // past the current character, decrement scrollAmount by the charWidth and move to the next character +- while (scrollInfo.pixelPos + scrollAmount >= charWidth) +- { +- scrollAmount -= (charWidth - scrollInfo.pixelPos); +- scrollInfo.pixelPos = 0; +- scrollInfo.characterPos++; +- if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size()) +- { +- scrollInfo.Reset(); +- break; +- } +- charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); +- } +- } +- } +- else if (scrollInfo.pixelSpeed < 0) +- { // scrolling backwards +- // we want to move scrollAmount, grab the next character +- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); +- if (scrollInfo.pixelPos + scrollAmount < charWidth) +- scrollInfo.pixelPos += scrollAmount; // within the current character +- else +- { // past the current character, decrement scrollAmount by the charWidth and move to the next character +- while (scrollInfo.pixelPos + scrollAmount >= charWidth) +- { +- scrollAmount -= (charWidth - scrollInfo.pixelPos); +- scrollInfo.pixelPos = 0; +- if (scrollInfo.characterPos == 0) +- { +- scrollInfo.Reset(); +- scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1; +- break; +- } +- scrollInfo.characterPos--; +- charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); +- } +- } ++ /* Calculate the pixel width of the complete string */ ++ scrollInfo.m_textWidth = GetTextWidth(text); ++ scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix); ++ scrollInfo.m_widthValid = true; + } ++ scrollInfo.pixelPos += scrollAmount; ++ assert(scrollInfo.m_totalWidth != 0); ++ while (scrollInfo.pixelPos >= scrollInfo.m_totalWidth) ++ scrollInfo.pixelPos -= scrollInfo.m_totalWidth; + +- if(scrollInfo.characterPos != old.characterPos +- || scrollInfo.pixelPos != old.pixelPos) ++ if (scrollInfo.pixelPos != old.pixelPos) + return true; + else + return false; +@@ -194,39 +165,27 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo + if (!m_font) return; + if (!shadowColor) shadowColor = m_shadowColor; + +- float spaceWidth = GetCharWidth(L' '); +- // max chars on screen + extra margin chars +- vecText::size_type maxChars = +- std::min( +- (text.size() + (vecText::size_type)scrollInfo.suffix.size()), +- (vecText::size_type)((maxWidth * 1.05f) / spaceWidth)); +- + if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment)) + return; // nothing to render + +- maxWidth = ROUND((maxWidth + scrollInfo.pixelPos) / g_graphicsContext.GetGUIScaleX()); ++ if (!scrollInfo.m_widthValid) ++ { ++ /* Calculate the pixel width of the complete string */ ++ scrollInfo.m_textWidth = GetTextWidth(text); ++ scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix); ++ scrollInfo.m_widthValid = true; ++ } ++ ++ assert(scrollInfo.m_totalWidth != 0); ++ ++ float textPixelWidth = ROUND(scrollInfo.m_textWidth / g_graphicsContext.GetGUIScaleX()); ++ float suffixPixelWidth = ROUND((scrollInfo.m_totalWidth - scrollInfo.m_textWidth) / g_graphicsContext.GetGUIScaleX()); + +- float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text)); + float offset; + if(scrollInfo.pixelSpeed >= 0) + offset = scrollInfo.pixelPos; + else +- offset = charWidth - scrollInfo.pixelPos; +- +- // Now rotate our string as needed, only take a slightly larger then visible part of the text. +- unsigned int pos = scrollInfo.characterPos; +- vecText renderText; +- renderText.reserve(maxChars); +- for (vecText::size_type i = 0; i < maxChars; i++) +- { +- if (pos >= text.size() + scrollInfo.suffix.size()) +- pos = 0; +- if (pos < text.size()) +- renderText.push_back(text[pos]); +- else +- renderText.push_back(scrollInfo.suffix[pos - text.size()]); +- pos++; +- } ++ offset = scrollInfo.m_totalWidth - scrollInfo.pixelPos; + + vecColors renderColors; + for (unsigned int i = 0; i < colors.size(); i++) +@@ -239,9 +198,17 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo + vecColors shadowColors; + for (unsigned int i = 0; i < renderColors.size(); i++) + shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0); +- m_font->DrawTextInternal(x - offset + 1, y + 1, shadowColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll); ++ for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth) ++ { ++ m_font->DrawTextInternal(x + dx + 1, y + 1, shadowColors, text, alignment, textPixelWidth, scroll); ++ m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll); ++ } ++ } ++ for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth) ++ { ++ m_font->DrawTextInternal(x + dx, y, renderColors, text, alignment, textPixelWidth, scroll); ++ m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth, y, renderColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll); + } +- m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll); + + g_graphicsContext.RestoreClipRegion(); + } +diff --git a/xbmc/guilib/GUIFont.h b/xbmc/guilib/GUIFont.h +index c55db48..09cf9b3 100644 +--- a/xbmc/guilib/GUIFont.h ++++ b/xbmc/guilib/GUIFont.h +@@ -64,7 +64,6 @@ class CScrollInfo + void Reset() + { + waitTime = initialWait; +- characterPos = 0; + // pixelPos is where we start the current letter, so is measured + // to the left of the text rendering's left edge. Thus, a negative + // value will mean the text starts to the right +@@ -72,25 +71,19 @@ class CScrollInfo + // privates: + m_averageFrameTime = 1000.f / abs(defaultSpeed); + m_lastFrameTime = 0; +- } +- uint32_t GetCurrentChar(const vecText &text) const +- { +- assert(text.size()); +- if (characterPos < text.size()) +- return text[characterPos]; +- else if (characterPos < text.size() + suffix.size()) +- return suffix[characterPos - text.size()]; +- return text[0]; ++ m_widthValid = false; + } + float GetPixelsPerFrame(); + + float pixelPos; + float pixelSpeed; + unsigned int waitTime; +- unsigned int characterPos; + unsigned int initialWait; + float initialPos; +- CStdStringW suffix; ++ vecText suffix; ++ mutable float m_textWidth; ++ mutable float m_totalWidth; ++ mutable bool m_widthValid; + + static const int defaultSpeed = 60; + private: +diff --git a/xbmc/guilib/GUIRSSControl.cpp b/xbmc/guilib/GUIRSSControl.cpp +index 8d985cf..a8e20fc 100644 +--- a/xbmc/guilib/GUIRSSControl.cpp ++++ b/xbmc/guilib/GUIRSSControl.cpp +@@ -119,7 +119,9 @@ void CGUIRSSControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyre + dirty = true; + + if (CRssManager::Get().GetReader(GetID(), GetParentID(), this, m_pReader)) +- m_scrollInfo.characterPos = m_pReader->m_SavedScrollPos; ++ { ++ m_scrollInfo.pixelPos = m_pReader->m_savedScrollPixelPos; ++ } + else + { + if (m_strRSSTags != "") +@@ -174,7 +176,7 @@ void CGUIRSSControl::Render() + if (m_pReader) + { + m_pReader->CheckForUpdates(); +- m_pReader->m_SavedScrollPos = m_scrollInfo.characterPos; ++ m_pReader->m_savedScrollPixelPos = m_scrollInfo.pixelPos; + } + } + CGUIControl::Render(); +diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp +index 5383156..41f9bc2 100644 +--- a/xbmc/utils/RssReader.cpp ++++ b/xbmc/utils/RssReader.cpp +@@ -55,7 +55,7 @@ CRssReader::CRssReader() : CThread("RSSReader") + m_pObserver = NULL; + m_spacesBetweenFeeds = 0; + m_bIsRunning = false; +- m_SavedScrollPos = 0; ++ m_savedScrollPixelPos = 0; + m_rtlText = false; + m_requestRefresh = false; + } +diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h +index 2cda726..fbc579e 100644 +--- a/xbmc/utils/RssReader.h ++++ b/xbmc/utils/RssReader.h +@@ -43,7 +43,7 @@ class CRssReader : public CThread + void SetObserver(IRssObserver* observer); + void CheckForUpdates(); + void requestRefresh(); +- unsigned int m_SavedScrollPos; ++ float m_savedScrollPixelPos; + + private: + void Process(); + +From 7bedebd03ff7a7986f178714a3586a07c3d5a9b5 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Mon, 27 Jan 2014 23:21:10 +0000 +Subject: [PATCH 25/77] Move the application of the translation offsets into + the GLES code. + +Still all pure software at this stage. Main change is in the data types at +the interface between CGUIFontTTFBase and CGUIFontTTFGL. The old way +(array of vertices in m_vertex) are retained in addition, for the sake`of +cases that need to use software clipping on GLES, as well as for DX and GL +support where the new scheme is not (yet?) used. +--- + xbmc/guilib/GUIFontTTF.cpp | 19 +++--------- + xbmc/guilib/GUIFontTTF.h | 17 +++++++++++ + xbmc/guilib/GUIFontTTFGL.cpp | 72 ++++++++++++++++++++++++++++++++------------ + 3 files changed, 73 insertions(+), 35 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index 412f47a..b0e69c0 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -214,6 +214,7 @@ void CGUIFontTTFBase::Clear() + g_freeTypeLibrary.ReleaseStroker(m_stroker); + m_stroker = NULL; + ++ m_vertexTrans.clear(); + m_vertex.clear(); + } + +@@ -309,6 +310,7 @@ void CGUIFontTTFBase::Begin() + { + if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin()) + { ++ m_vertexTrans.clear(); + m_vertex.clear(); + } + // Keep track of the nested begin/end calls. +@@ -456,23 +458,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + cursorX += ch->advance; + } + if (hardwareClipping) +- /* Append the new vertices (which we have just constructed in the cache) +- * to the set collected since the first Begin() call */ +- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); ++ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices)); + } + else if (hardwareClipping) +- { +- /* Apply the translation offset to the vertices from the cache after +- * appending them to the set collected since the first Begin() call */ +- m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end()); +- SVertex *v; +- for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++) +- { +- v->x += dynamicPos.m_x; +- v->y += dynamicPos.m_y; +- v->z += dynamicPos.m_z; +- } +- } ++ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices)); + if (!hardwareClipping) + /* Append the new vertices (from the cache or otherwise) to the set collected + * since the first Begin() call */ +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index 39bfa52..e8afc1c 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -61,6 +61,14 @@ struct SVertex + unsigned char r, g, b, a; + #endif + float u, v; ++ struct SVertex Offset(float translate[3]) const ++ { ++ SVertex out = *this; ++ out.x += translate[0]; ++ out.y += translate[1]; ++ out.z += translate[2]; ++ return out; ++ } + }; + + +@@ -159,6 +167,15 @@ class CGUIFontTTFBase + + unsigned int m_nTexture; + ++ struct CTranslatedVertices ++ { ++ float translateX; ++ float translateY; ++ float translateZ; ++ const std::vector *vertexBuffer; ++ CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {} ++ }; ++ std::vector m_vertexTrans; + std::vector m_vertex; + + float m_textureScaleX; +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index 9935ea4..18c9358 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -167,34 +167,65 @@ void CGUIFontTTFGL::LastEnd() + GLint colLoc = g_Windowing.GUIShaderGetCol(); + GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); + +- // stack object until VBOs will be used +- std::vector vecVertices( 6 * (m_vertex.size() / 4) ); +- SVertex *vertices = &vecVertices[0]; ++ // Enable the attributes used by this shader ++ glEnableVertexAttribArray(posLoc); ++ glEnableVertexAttribArray(colLoc); ++ glEnableVertexAttribArray(tex0Loc); + +- for (size_t i=0; i 0) + { +- *vertices++ = m_vertex[i]; +- *vertices++ = m_vertex[i+1]; +- *vertices++ = m_vertex[i+2]; ++ // Deal with vertices that had to use software clipping ++ std::vector vecVertices( 6 * (m_vertex.size() / 4) ); ++ SVertex *vertices = &vecVertices[0]; + +- *vertices++ = m_vertex[i+1]; +- *vertices++ = m_vertex[i+3]; +- *vertices++ = m_vertex[i+2]; +- } ++ for (size_t i=0; i 0) ++ { ++ // Deal with the vertices that can be hardware clipped and therefore translated ++ std::vector vecVertices; ++ for (size_t i = 0; i < m_vertexTrans.size(); i++) ++ { ++ float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ }; ++ for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4) ++ { ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate)); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate)); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); ++ } ++ } ++ SVertex *vertices = &vecVertices[0]; + +- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); ++ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); ++ // Normalize color values. Does not affect Performance at all. ++ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); ++ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); ++ ++ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); ++ } + ++ // Disable the attributes used by this shader + glDisableVertexAttribArray(posLoc); + glDisableVertexAttribArray(colLoc); + glDisableVertexAttribArray(tex0Loc); +@@ -222,6 +253,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) + if (m_textureHeight < newHeight) + CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight); + m_staticCache.Flush(); ++ m_dynamicCache.Flush(); + + memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch()); + if (m_texture) + +From e0abdac7367737366a3d1054a2cef8568f6cd6ad Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 15 Jan 2014 15:28:06 +0000 +Subject: [PATCH 26/77] Rather than applying the translation offsets to the + vertices, now applies them to the model view matrix from the top of the + matrix stack and pushes it over to OpenGL. The vertices themselves are still + all held client-side. + +--- + xbmc/guilib/GUIFontTTF.h | 8 ------- + xbmc/guilib/GUIFontTTFGL.cpp | 40 +++++++++++++++++++++----------- + xbmc/guilib/GUIShader.h | 1 + + xbmc/rendering/gles/RenderSystemGLES.cpp | 8 +++++++ + xbmc/rendering/gles/RenderSystemGLES.h | 1 + + 5 files changed, 36 insertions(+), 22 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index e8afc1c..573039d 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -61,14 +61,6 @@ struct SVertex + unsigned char r, g, b, a; + #endif + float u, v; +- struct SVertex Offset(float translate[3]) const +- { +- SVertex out = *this; +- out.x += translate[0]; +- out.y += translate[1]; +- out.z += translate[2]; +- return out; +- } + }; + + +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index 18c9358..ea08bf4 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -29,6 +29,7 @@ + #include "utils/log.h" + #include "utils/GLUtils.h" + #include "windowing/WindowingFactory.h" ++#include "guilib/MatrixGLES.h" + + // stuff for freetype + #include +@@ -166,6 +167,7 @@ void CGUIFontTTFGL::LastEnd() + GLint posLoc = g_Windowing.GUIShaderGetPos(); + GLint colLoc = g_Windowing.GUIShaderGetCol(); + GLint tex0Loc = g_Windowing.GUIShaderGetCoord0(); ++ GLint modelLoc = g_Windowing.GUIShaderGetModel(); + + // Enable the attributes used by this shader + glEnableVertexAttribArray(posLoc); +@@ -204,25 +206,35 @@ void CGUIFontTTFGL::LastEnd() + std::vector vecVertices; + for (size_t i = 0; i < m_vertexTrans.size(); i++) + { +- float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ }; ++ // Apply the translation to the currently active (top-of-stack) model view matrix ++ g_matrices.MatrixMode(MM_MODELVIEW); ++ g_matrices.PushMatrix(); ++ g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ); ++ glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); ++ ++ vecVertices.clear(); + for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4) + { +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate)); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate)); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate)); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate)); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]); ++ vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); + } +- } +- SVertex *vertices = &vecVertices[0]; ++ SVertex *vertices = &vecVertices[0]; + +- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); +- // Normalize color values. Does not affect Performance at all. +- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); +- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); ++ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); ++ // Normalize color values. Does not affect Performance at all. ++ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); ++ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); + +- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); ++ glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); ++ ++ g_matrices.PopMatrix(); ++ } ++ // Restore the original model view matrix ++ glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); + } + + // Disable the attributes used by this shader +diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h +index fdf7452..abbe21c 100644 +--- a/xbmc/guilib/GUIShader.h ++++ b/xbmc/guilib/GUIShader.h +@@ -39,6 +39,7 @@ class CGUIShader : public Shaders::CGLSLShaderProgram + GLint GetCord1Loc() { return m_hCord1; } + GLint GetUniColLoc() { return m_hUniCol; } + GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; } ++ GLint GetModelLoc() { return m_hModel; } + bool HardwareClipIsPossible() { return m_clipPossible; } + GLfloat GetClipXFactor() { return m_clipXFactor; } + GLfloat GetClipXOffset() { return m_clipXOffset; } +diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp +index deb3afc..0904d1f 100644 +--- a/xbmc/rendering/gles/RenderSystemGLES.cpp ++++ b/xbmc/rendering/gles/RenderSystemGLES.cpp +@@ -691,4 +691,12 @@ bool CRenderSystemGLES::SupportsStereo(RENDER_STEREO_MODE mode) + } + } + ++GLint CRenderSystemGLES::GUIShaderGetModel() ++{ ++ if (m_pGUIshader[m_method]) ++ return m_pGUIshader[m_method]->GetModelLoc(); ++ ++ return -1; ++} ++ + #endif +diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h +index 81ee49e..d2f9cd1 100644 +--- a/xbmc/rendering/gles/RenderSystemGLES.h ++++ b/xbmc/rendering/gles/RenderSystemGLES.h +@@ -91,6 +91,7 @@ class CRenderSystemGLES : public CRenderSystemBase + GLint GUIShaderGetCoord1(); + GLint GUIShaderGetUniCol(); + GLint GUIShaderGetCoord0Matrix(); ++ GLint GUIShaderGetModel(); + + protected: + virtual void SetVSyncImpl(bool enable) = 0; + +From 54e3057566feeaea70e61b7d5173857a37cfad23 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 29 Jan 2014 13:21:19 +0000 +Subject: [PATCH 27/77] Enable hardware clipping. + +--- + xbmc/guilib/GUIFontTTF.cpp | 4 ++-- + xbmc/guilib/GUIFontTTF.h | 5 ++++- + xbmc/guilib/GUIFontTTFGL.cpp | 6 ++++++ + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index b0e69c0..3ea1051 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -458,10 +458,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + cursorX += ch->advance; + } + if (hardwareClipping) +- m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices)); ++ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion())); + } + else if (hardwareClipping) +- m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices)); ++ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion())); + if (!hardwareClipping) + /* Append the new vertices (from the cache or otherwise) to the set collected + * since the first Begin() call */ +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index 573039d..a6931c1 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -27,6 +27,8 @@ + * + */ + ++#include "Geometry.h" ++ + // forward definition + class CBaseTexture; + +@@ -165,7 +167,8 @@ class CGUIFontTTFBase + float translateY; + float translateZ; + const std::vector *vertexBuffer; +- CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {} ++ CRect clip; ++ CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {} + }; + std::vector m_vertexTrans; + std::vector m_vertex; +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index ea08bf4..b63e337 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -206,6 +206,10 @@ void CGUIFontTTFGL::LastEnd() + std::vector vecVertices; + for (size_t i = 0; i < m_vertexTrans.size(); i++) + { ++ // Apply the clip rectangle ++ CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip); ++ g_Windowing.SetScissors(clip); ++ + // Apply the translation to the currently active (top-of-stack) model view matrix + g_matrices.MatrixMode(MM_MODELVIEW); + g_matrices.PushMatrix(); +@@ -233,6 +237,8 @@ void CGUIFontTTFGL::LastEnd() + + g_matrices.PopMatrix(); + } ++ // Restore the original scissor rectangle ++ g_Windowing.ResetScissors(); + // Restore the original model view matrix + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); + } + +From 73c558a08f0441236fb44e408c4ad507d27e056a Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 15 Jan 2014 15:32:51 +0000 +Subject: [PATCH 28/77] Move the vertex data across to a vertex buffer object + just prior to drawing. + +--- + xbmc/guilib/GUIFontTTFGL.cpp | 24 +++++++++++++++++++----- + 1 file changed, 19 insertions(+), 5 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index b63e337..b00055d 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -228,12 +228,24 @@ void CGUIFontTTFGL::LastEnd() + } + SVertex *vertices = &vecVertices[0]; + +- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x)); +- // Normalize color values. Does not affect Performance at all. +- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r)); +- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u)); +- ++ // Generate a unique buffer object name and put it in vertexBuffer ++ GLuint vertexBuffer; ++ glGenBuffers(1, &vertexBuffer); ++ // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point ++ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); ++ // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER ++ // binding point (i.e. our buffer object) and initialise it from the ++ // specified client-side pointer ++ glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW); ++ // Set up the offsets of the various vertex attributes within the buffer ++ // object bound to GL_ARRAY_BUFFER ++ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x)); ++ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r)); ++ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u)); ++ // Do the actual drawing operation, using the full set of vertices in the buffer + glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); ++ // Release the buffer name for reuse ++ glDeleteBuffers(1, &vertexBuffer); + + g_matrices.PopMatrix(); + } +@@ -241,6 +253,8 @@ void CGUIFontTTFGL::LastEnd() + g_Windowing.ResetScissors(); + // Restore the original model view matrix + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); ++ // Unbind GL_ARRAY_BUFFER ++ glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + // Disable the attributes used by this shader + +From 1bdbf7a657217a2974e830f711a84d843f9f574f Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 15 Jan 2014 16:04:04 +0000 +Subject: [PATCH 29/77] Move vertex data into an OpenGL VBO when the font cache + entry is populated. + +The font cache now stores the "name" (handle) of the VBO, rather than a vector +of vertices. +--- + xbmc/guilib/GUIFontCache.cpp | 6 ++++ + xbmc/guilib/GUIFontCache.h | 30 +++++++++++++++++- + xbmc/guilib/GUIFontTTF.cpp | 15 +++++++-- + xbmc/guilib/GUIFontTTF.h | 7 +++-- + xbmc/guilib/GUIFontTTFGL.cpp | 74 ++++++++++++++++++++++++++++++-------------- + xbmc/guilib/GUIFontTTFGL.h | 5 +++ + 6 files changed, 107 insertions(+), 30 deletions(-) + +diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp +index df466a5..bd84b9a 100644 +--- a/xbmc/guilib/GUIFontCache.cpp ++++ b/xbmc/guilib/GUIFontCache.cpp +@@ -111,3 +111,9 @@ template void CGUIFontCacheEntry::~CGUIFontCacheEntry(); + template CGUIFontCacheDynamicValue &CGUIFontCache::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &); + template void CGUIFontCache::Flush(); ++ ++void CVertexBuffer::clear() ++{ ++ if (m_font != NULL) ++ m_font->DestroyVertexBuffer(*this); ++} +diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h +index d913dee..ff766bf 100644 +--- a/xbmc/guilib/GUIFontCache.h ++++ b/xbmc/guilib/GUIFontCache.h +@@ -234,7 +234,35 @@ struct CGUIFontCacheDynamicPosition + } + }; + +-typedef std::vector CGUIFontCacheDynamicValue; ++struct CVertexBuffer ++{ ++ void *bufferHandle; ++ size_t size; ++ CVertexBuffer() : bufferHandle(NULL), size(0), m_font(NULL) {} ++ CVertexBuffer(void *bufferHandle, size_t size, const CGUIFontTTFBase *font) : bufferHandle(bufferHandle), size(size), m_font(font) {} ++ CVertexBuffer(const CVertexBuffer &other) : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font) ++ { ++ /* In practice, the copy constructor is only called before a vertex buffer ++ * has been attached. If this should ever change, we'll need another support ++ * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */ ++ assert(other.bufferHandle == 0); ++ } ++ CVertexBuffer &operator=(CVertexBuffer &other) ++ { ++ /* This is used with move-assignment semantics for initialising the object in the font cache */ ++ assert(bufferHandle == 0); ++ bufferHandle = other.bufferHandle; ++ other.bufferHandle = 0; ++ size = other.size; ++ m_font = other.m_font; ++ return *this; ++ } ++ void clear(); ++private: ++ const CGUIFontTTFBase *m_font; ++}; ++ ++typedef CVertexBuffer CGUIFontCacheDynamicValue; + + inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m, + const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m, +diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp +index 3ea1051..ea510f4 100644 +--- a/xbmc/guilib/GUIFontTTF.cpp ++++ b/xbmc/guilib/GUIFontTTF.cpp +@@ -342,13 +342,18 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + g_graphicsContext.ScaleFinalYCoord(x, y), + g_graphicsContext.ScaleFinalZCoord(x, y)); + } +- std::vector &vertices = hardwareClipping ? ++ CVertexBuffer unusedVertexBuffer; ++ CVertexBuffer &vertexBuffer = hardwareClipping ? + m_dynamicCache.Lookup(dynamicPos, + colors, text, + alignment, maxPixelWidth, + scrolling, + XbmcThreads::SystemClockMillis(), + dirtyCache) : ++ unusedVertexBuffer; ++ std::vector tempVertices; ++ std::vector &vertices = hardwareClipping ? ++ tempVertices : + m_staticCache.Lookup(staticPos, + colors, text, + alignment, maxPixelWidth, +@@ -458,10 +463,14 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors + cursorX += ch->advance; + } + if (hardwareClipping) +- m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion())); ++ { ++ CVertexBuffer newVertexBuffer = CreateVertexBuffer(tempVertices); ++ vertexBuffer = newVertexBuffer; ++ m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion())); ++ } + } + else if (hardwareClipping) +- m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion())); ++ m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, g_graphicsContext.GetClipRegion())); + if (!hardwareClipping) + /* Append the new vertices (from the cache or otherwise) to the set collected + * since the first Begin() call */ +diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h +index a6931c1..9a35ac4 100644 +--- a/xbmc/guilib/GUIFontTTF.h ++++ b/xbmc/guilib/GUIFontTTF.h +@@ -84,6 +84,9 @@ class CGUIFontTTFBase + + void Begin(); + void End(); ++ /* The next two should only be called if we've declared we can do hardware clipping */ ++ virtual CVertexBuffer CreateVertexBuffer(const std::vector &vertices) const { assert(false); return CVertexBuffer(); } ++ virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const {} + + const CStdString& GetFileName() const { return m_strFileName; }; + +@@ -166,9 +169,9 @@ class CGUIFontTTFBase + float translateX; + float translateY; + float translateZ; +- const std::vector *vertexBuffer; ++ const CVertexBuffer *vertexBuffer; + CRect clip; +- CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {} ++ CTranslatedVertices(float translateX, float translateY, float translateZ, const CVertexBuffer *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {} + }; + std::vector m_vertexTrans; + std::vector m_vertex; +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index b00055d..aabb9a6 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -52,6 +52,10 @@ CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName) + + CGUIFontTTFGL::~CGUIFontTTFGL(void) + { ++ // It's important that all the CGUIFontCacheEntry objects are ++ // destructed before the CGUIFontTTFGL goes out of scope, because ++ // our virtual methods won't be accessible after this point ++ m_dynamicCache.Flush(); + } + + bool CGUIFontTTFGL::FirstBegin() +@@ -203,7 +207,6 @@ void CGUIFontTTFGL::LastEnd() + if (m_vertexTrans.size() > 0) + { + // Deal with the vertices that can be hardware clipped and therefore translated +- std::vector vecVertices; + for (size_t i = 0; i < m_vertexTrans.size(); i++) + { + // Apply the clip rectangle +@@ -216,36 +219,17 @@ void CGUIFontTTFGL::LastEnd() + g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ); + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); + +- vecVertices.clear(); +- for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4) +- { +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]); +- vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]); +- } +- SVertex *vertices = &vecVertices[0]; +- +- // Generate a unique buffer object name and put it in vertexBuffer +- GLuint vertexBuffer; +- glGenBuffers(1, &vertexBuffer); + // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point +- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); +- // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER +- // binding point (i.e. our buffer object) and initialise it from the +- // specified client-side pointer +- glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW); ++ glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle); ++ + // Set up the offsets of the various vertex attributes within the buffer + // object bound to GL_ARRAY_BUFFER + glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x)); + glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r)); + glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u)); ++ + // Do the actual drawing operation, using the full set of vertices in the buffer +- glDrawArrays(GL_TRIANGLES, 0, vecVertices.size()); +- // Release the buffer name for reuse +- glDeleteBuffers(1, &vertexBuffer); ++ glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size); + + g_matrices.PopMatrix(); + } +@@ -266,6 +250,48 @@ void CGUIFontTTFGL::LastEnd() + #endif + } + ++#if HAS_GLES ++CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector &vertices) const ++{ ++ // Rearrange the vertices to describe triangles ++ std::vector triangleVertices; ++ triangleVertices.reserve(vertices.size() * 6 / 4); ++ for (size_t i = 0; i < vertices.size(); i += 4) ++ { ++ triangleVertices.push_back(vertices[i]); ++ triangleVertices.push_back(vertices[i+1]); ++ triangleVertices.push_back(vertices[i+2]); ++ triangleVertices.push_back(vertices[i+1]); ++ triangleVertices.push_back(vertices[i+3]); ++ triangleVertices.push_back(vertices[i+2]); ++ } ++ ++ // Generate a unique buffer object name and put it in bufferHandle ++ GLuint bufferHandle; ++ glGenBuffers(1, &bufferHandle); ++ // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point ++ glBindBuffer(GL_ARRAY_BUFFER, bufferHandle); ++ // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER ++ // binding point (i.e. our buffer object) and initialise it from the ++ // specified client-side pointer ++ glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW); ++ // Unbind GL_ARRAY_BUFFER ++ glBindBuffer(GL_ARRAY_BUFFER, 0); ++ ++ return CVertexBuffer((void *) bufferHandle, vertices.size() / 4, this); ++} ++ ++void CGUIFontTTFGL::DestroyVertexBuffer(CVertexBuffer &buffer) const ++{ ++ if (buffer.bufferHandle != 0) ++ { ++ // Release the buffer name for reuse ++ glDeleteBuffers(1, (GLuint *) &buffer.bufferHandle); ++ buffer.bufferHandle = 0; ++ } ++} ++#endif ++ + CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight) + { + newHeight = CBaseTexture::PadPow2(newHeight); +diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h +index 735fb3a..6102c90 100644 +--- a/xbmc/guilib/GUIFontTTFGL.h ++++ b/xbmc/guilib/GUIFontTTFGL.h +@@ -29,6 +29,7 @@ + + + #include "GUIFontTTF.h" ++#include "system.h" + + + /*! +@@ -43,6 +44,10 @@ class CGUIFontTTFGL : public CGUIFontTTFBase + + virtual bool FirstBegin(); + virtual void LastEnd(); ++#if HAS_GLES ++ virtual CVertexBuffer CreateVertexBuffer(const std::vector &vertices) const; ++ virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const; ++#endif + + protected: + virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); + +From 774a3446b96a8c39b7a98a5e0663564893d50965 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Thu, 16 Jan 2014 16:29:42 +0000 +Subject: [PATCH 30/77] Switch from glDrawArrays() to glDrawElements(). + +This involves setting up a static VBO containing the indexes necessary to +convert from quads to triangles on the fly in the GPU. +--- + xbmc/guilib/GUIFontTTFGL.cpp | 72 +++++++++++++++++++++++++------------ + xbmc/guilib/GUIFontTTFGL.h | 11 +++++- + xbmc/windowing/egl/WinSystemEGL.cpp | 17 +++++++++ + 3 files changed, 77 insertions(+), 23 deletions(-) + +diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp +index aabb9a6..812662c 100644 +--- a/xbmc/guilib/GUIFontTTFGL.cpp ++++ b/xbmc/guilib/GUIFontTTFGL.cpp +@@ -207,6 +207,10 @@ void CGUIFontTTFGL::LastEnd() + if (m_vertexTrans.size() > 0) + { + // Deal with the vertices that can be hardware clipped and therefore translated ++ ++ // Bind our pre-calculated array to GL_ELEMENT_ARRAY_BUFFER ++ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle); ++ + for (size_t i = 0; i < m_vertexTrans.size(); i++) + { + // Apply the clip rectangle +@@ -222,14 +226,21 @@ void CGUIFontTTFGL::LastEnd() + // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point + glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle); + +- // Set up the offsets of the various vertex attributes within the buffer +- // object bound to GL_ARRAY_BUFFER +- glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x)); +- glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, r)); +- glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u)); ++ // Do the actual drawing operation, split into groups of characters no ++ // larger than the pre-determined size of the element array ++ for (size_t character = 0; m_vertexTrans[i].vertexBuffer->size > character; character += ELEMENT_ARRAY_MAX_CHAR_INDEX) ++ { ++ size_t count = m_vertexTrans[i].vertexBuffer->size - character; ++ count = std::min(count, ELEMENT_ARRAY_MAX_CHAR_INDEX); ++ ++ // Set up the offsets of the various vertex attributes within the buffer ++ // object bound to GL_ARRAY_BUFFER ++ glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, x))); ++ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, r))); ++ glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, u))); + +- // Do the actual drawing operation, using the full set of vertices in the buffer +- glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size); ++ glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0); ++ } + + g_matrices.PopMatrix(); + } +@@ -237,8 +248,9 @@ void CGUIFontTTFGL::LastEnd() + g_Windowing.ResetScissors(); + // Restore the original model view matrix + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW)); +- // Unbind GL_ARRAY_BUFFER ++ // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER + glBindBuffer(GL_ARRAY_BUFFER, 0); ++ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + // Disable the attributes used by this shader +@@ -253,19 +265,6 @@ void CGUIFontTTFGL::LastEnd() + #if HAS_GLES + CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector &vertices) const + { +- // Rearrange the vertices to describe triangles +- std::vector triangleVertices; +- triangleVertices.reserve(vertices.size() * 6 / 4); +- for (size_t i = 0; i < vertices.size(); i += 4) +- { +- triangleVertices.push_back(vertices[i]); +- triangleVertices.push_back(vertices[i+1]); +- triangleVertices.push_back(vertices[i+2]); +- triangleVertices.push_back(vertices[i+1]); +- triangleVertices.push_back(vertices[i+3]); +- triangleVertices.push_back(vertices[i+2]); +- } +- + // Generate a unique buffer object name and put it in bufferHandle + GLuint bufferHandle; + glGenBuffers(1, &bufferHandle); +@@ -274,7 +273,7 @@ CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector &vert + // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER + // binding point (i.e. our buffer object) and initialise it from the + // specified client-side pointer +- glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW); ++ glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), &vertices[0], GL_STATIC_DRAW); + // Unbind GL_ARRAY_BUFFER + glBindBuffer(GL_ARRAY_BUFFER, 0); + +@@ -393,4 +392,33 @@ void CGUIFontTTFGL::DeleteHardwareTexture() + } + } + ++#if HAS_GLES ++void CGUIFontTTFGL::CreateStaticVertexBuffers(void) ++{ ++ // Bind a new buffer to the OpenGL context's GL_ELEMENT_ARRAY_BUFFER binding point ++ glGenBuffers(1, &m_elementArrayHandle); ++ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle); ++ // Create an array holding the mesh indices to convert quads to triangles ++ GLushort index[ELEMENT_ARRAY_MAX_CHAR_INDEX][6]; ++ for (size_t i = 0; i < ELEMENT_ARRAY_MAX_CHAR_INDEX; i++) ++ { ++ index[i][0] = 4*i; ++ index[i][1] = 4*i+1; ++ index[i][2] = 4*i+2; ++ index[i][3] = 4*i+1; ++ index[i][4] = 4*i+3; ++ index[i][5] = 4*i+2; ++ } ++ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof index, index, GL_STATIC_DRAW); ++ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); ++} ++ ++void CGUIFontTTFGL::DestroyStaticVertexBuffers(void) ++{ ++ glDeleteBuffers(1, &m_elementArrayHandle); ++} ++ ++GLuint CGUIFontTTFGL::m_elementArrayHandle; ++#endif ++ + #endif +diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h +index 6102c90..dcf9ca1 100644 +--- a/xbmc/guilib/GUIFontTTFGL.h ++++ b/xbmc/guilib/GUIFontTTFGL.h +@@ -30,6 +30,7 @@ + + #include "GUIFontTTF.h" + #include "system.h" ++#include "system_gl.h" + + + /*! +@@ -47,13 +48,21 @@ class CGUIFontTTFGL : public CGUIFontTTFBase + #if HAS_GLES + virtual CVertexBuffer CreateVertexBuffer(const std::vector &vertices) const; + virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const; ++ static void CreateStaticVertexBuffers(void); ++ static void DestroyStaticVertexBuffers(void); + #endif + + protected: + virtual CBaseTexture* ReallocTexture(unsigned int& newHeight); + virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2); + virtual void DeleteHardwareTexture(); +- ++ ++#if HAS_GLES ++#define ELEMENT_ARRAY_MAX_CHAR_INDEX (1000) ++ ++ static GLuint m_elementArrayHandle; ++#endif ++ + private: + unsigned int m_updateY1; + unsigned int m_updateY2; +diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp +index 6de3532..258a293 100644 +--- a/xbmc/windowing/egl/WinSystemEGL.cpp ++++ b/xbmc/windowing/egl/WinSystemEGL.cpp +@@ -29,6 +29,7 @@ + #include "settings/AdvancedSettings.h" + #include "settings/Settings.h" + #include "settings/DisplaySettings.h" ++#include "guilib/GUIFontTTFGL.h" + #include "utils/log.h" + #include "EGLWrapper.h" + #include "EGLQuirks.h" +@@ -193,6 +194,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res) + return false; + } + ++#if HAS_GLES ++ bool newContext = false; ++#endif + if (m_context == EGL_NO_CONTEXT) + { + if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context)) +@@ -200,6 +204,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res) + CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__); + return false; + } ++#if HAS_GLES ++ newContext = true; ++#endif + } + + if (!m_egl->BindContext(m_display, m_surface, m_context)) +@@ -208,6 +215,11 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res) + return false; + } + ++#if HAS_GLES ++ if (newContext) ++ CGUIFontTTFGL::CreateStaticVertexBuffers(); ++#endif ++ + // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates + if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION || + g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION) +@@ -229,7 +241,12 @@ bool CWinSystemEGL::DestroyWindowSystem() + DestroyWindow(); + + if (m_context != EGL_NO_CONTEXT) ++ { ++#if HAS_GLES ++ CGUIFontTTFGL::DestroyStaticVertexBuffers(); ++#endif + m_egl->DestroyContext(m_display, m_context); ++ } + m_context = EGL_NO_CONTEXT; + + if (m_display != EGL_NO_DISPLAY) + +From 09468bf68f2b5047849b0731d46bb5528cee6d4d Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Thu, 1 May 2014 16:28:39 +0100 +Subject: [PATCH 31/77] Improved file buffering in CArchive + +Even though memcpy is typically inlined by the compiler into byte/word loads +and stores (at least for release builds), the frequency with which 1, 2 and 4 +byte loads/stores are encountered in cases where the size is *not* +determinable at compile time is still high enough that it's worth handling +these specially. On the ARM1176JZF-S in the Raspberry Pi, this improves the +total time to open a library (in the case where it's fetched from a CArchive) +by around 4%. + +It should be noted that this code uses 16-bit and 32-bit word loads and +stores that are not necessarily aligned to their respective widths. It is +possible that there are some architectures out there which do not support +this, although all ARMs since ARMv6 have supported it (and ARMs earlier than +that are probably not powerful enough to be good targets for XBMC). +--- + xbmc/utils/Archive.h | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h +index 6ed0f8f..8506d95 100644 +--- a/xbmc/utils/Archive.h ++++ b/xbmc/utils/Archive.h +@@ -154,9 +154,17 @@ class CArchive + * than waiting until we attempt to put more data into an already full buffer */ + if (m_BufferRemain > size) + { ++ switch (size) ++ { ++ case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break; ++ case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break; ++ case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break; ++ default: + memcpy(m_BufferPos, ptr, size); + m_BufferPos += size; + m_BufferRemain -= size; ++ break; ++ } + return *this; + } + else +@@ -171,9 +179,17 @@ class CArchive + /* Note, refilling the buffer is deferred until we know we need to read more from it */ + if (m_BufferRemain >= size) + { ++ switch (size) ++ { ++ case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break; ++ case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break; ++ case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break; ++ default: + memcpy(ptr, m_BufferPos, size); + m_BufferPos += size; + m_BufferRemain -= size; ++ break; ++ } + return *this; + } + else + +From 6ce2c7d35b7ca4355b7cd687ecbc29238d28808c Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 9 Jul 2014 01:14:23 +0100 +Subject: [PATCH 32/77] [omxcodec] Switch to MMAL decoder with MMAL renderer + +--- + configure.in | 23 +- + language/English/strings.po | 2 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 78 - + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 8 +- + xbmc/cores/VideoRenderers/Makefile.in | 1 + + xbmc/cores/VideoRenderers/OMXRenderer.cpp | 784 +++++++++ + xbmc/cores/VideoRenderers/OMXRenderer.h | 129 ++ + xbmc/cores/VideoRenderers/RenderManager.cpp | 6 +- + xbmc/cores/VideoRenderers/RenderManager.h | 3 + + xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 9 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 7 +- + .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp | 301 +--- + .../DVDCodecs/Video/DVDVideoCodecOpenMax.h | 38 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 1 - + .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 1727 ++++++++++---------- + .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 165 +- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 2 +- + 17 files changed, 1975 insertions(+), 1309 deletions(-) + create mode 100644 xbmc/cores/VideoRenderers/OMXRenderer.cpp + create mode 100644 xbmc/cores/VideoRenderers/OMXRenderer.h + +diff --git a/configure.in b/configure.in +index fcb7b62..c0ea777 100644 +--- a/configure.in ++++ b/configure.in +@@ -1003,7 +1003,7 @@ if test "$use_gles" = "yes"; then + AC_DEFINE([HAVE_LIBEGL],[1],["Define to 1 if you have the `EGL' library (-lEGL)."]) + AC_DEFINE([HAVE_LIBGLESV2],[1],["Define to 1 if you have the `GLESv2' library (-lGLESv2)."]) + AC_MSG_RESULT(== WARNING: OpenGLES support is assumed.) +- LIBS="$LIBS -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm" ++ LIBS="$LIBS -lEGL -lGLESv2 -lbcm_host -lvcos -lvchiq_arm -lvchiq_arm -lmmal -lmmal_core -lmmal_util" + else + AC_CHECK_LIB([EGL], [main],, AC_MSG_ERROR($missing_library)) + AC_CHECK_LIB([GLESv2],[main],, AC_MSG_ERROR($missing_library)) +@@ -1865,9 +1865,24 @@ if test "$host_vendor" = "apple" ; then + USE_OPENMAX=0 + AC_MSG_NOTICE($openmax_disabled) + elif test "$target_platform" = "target_raspberry_pi"; then +- use_openmax="no" +- USE_OPENMAX=0 +- AC_MSG_NOTICE($openmax_disabled) ++ if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then ++ use_openmax="yes" ++ USE_OPENMAX=1 ++ HAVE_LIBOPENMAX=1 ++ AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.]) ++ AC_DEFINE([OMX_SKIP64BIT], [1], [Define to 1 if you have the 'LIBOPENMAX' library.]) ++ AC_MSG_NOTICE($openmax_enabled) ++ elif test "$use_gles" = "yes" && test "$use_openmax" = "yes"; then ++ use_openmax="yes" ++ USE_OPENMAX=1 ++ HAVE_LIBOPENMAX=1 ++ AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.]) ++ AC_MSG_NOTICE($openmax_enabled) ++ else ++ AC_MSG_NOTICE($openmax_disabled) ++ use_openmax=no ++ USE_OPENMAX=0 ++ fi + else + if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then + PKG_CHECK_MODULES([OPENMAX], [libomxil-bellagio], +diff --git a/language/English/strings.po b/language/English/strings.po +index fea6e08..ade855e 100755 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -13864,7 +13864,7 @@ msgstr "" + #. Description of setting "Videos -> Playback -> Allow hardware acceleration (OpenMax)" with label #13430 + #: system/settings/settings.xml + msgctxt "#36161" +-msgid "Enable OpenMax hardware decoding of video files." ++msgid "Enable OpenMax hardware decoding of video files (using DVDPlayer)." + msgstr "" + + #. Description of setting "Videos -> Playback -> Allow hardware acceleration (VideoToolbox)" with label #13432 +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 8db4ea1..d946e03 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -101,9 +101,6 @@ CLinuxRendererGLES::YUVBUFFER::YUVBUFFER() + memset(&fields, 0, sizeof(fields)); + memset(&image , 0, sizeof(image)); + flipindex = 0; +-#ifdef HAVE_LIBOPENMAX +- openMaxBuffer = NULL; +-#endif + #ifdef HAVE_VIDEOTOOLBOXDECODER + cvBufferRef = NULL; + #endif +@@ -616,9 +613,6 @@ unsigned int CLinuxRendererGLES::PreInit() + m_formats.push_back(RENDER_FMT_YUV420P); + m_formats.push_back(RENDER_FMT_NV12); + m_formats.push_back(RENDER_FMT_BYPASS); +-#if defined(HAVE_LIBOPENMAX) +- m_formats.push_back(RENDER_FMT_OMXEGL); +-#endif + #ifdef HAVE_VIDEOTOOLBOXDECODER + m_formats.push_back(RENDER_FMT_CVBREF); + #endif +@@ -1369,67 +1363,6 @@ void CLinuxRendererGLES::RenderSoftware(int index, int field) + VerifyGLState(); + } + +-void CLinuxRendererGLES::RenderOpenMax(int index, int field) +-{ +-#if defined(HAVE_LIBOPENMAX) +- GLuint textureId = m_buffers[index].openMaxBuffer->texture_id; +- +- glDisable(GL_DEPTH_TEST); +- +- // Y +- glEnable(m_textureTarget); +- glActiveTexture(GL_TEXTURE0); +- glBindTexture(m_textureTarget, textureId); +- +- g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA); +- +- GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip +- GLfloat ver[4][4]; +- GLfloat tex[4][2]; +- GLfloat col[3] = {1.0f, 1.0f, 1.0f}; +- +- GLint posLoc = g_Windowing.GUIShaderGetPos(); +- GLint texLoc = g_Windowing.GUIShaderGetCoord0(); +- GLint colLoc = g_Windowing.GUIShaderGetCol(); +- +- glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver); +- glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex); +- glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col); +- +- glEnableVertexAttribArray(posLoc); +- glEnableVertexAttribArray(texLoc); +- glEnableVertexAttribArray(colLoc); +- +- // Set vertex coordinates +- for(int i = 0; i < 4; i++) +- { +- ver[i][0] = m_rotatedDestCoords[i].x; +- ver[i][1] = m_rotatedDestCoords[i].y; +- ver[i][2] = 0.0f;// set z to 0 +- ver[i][3] = 1.0f; +- } +- +- // Set texture coordinates +- tex[0][0] = tex[3][0] = 0; +- tex[0][1] = tex[1][1] = 0; +- tex[1][0] = tex[2][0] = 1; +- tex[2][1] = tex[3][1] = 1; +- +- glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx); +- +- glDisableVertexAttribArray(posLoc); +- glDisableVertexAttribArray(texLoc); +- glDisableVertexAttribArray(colLoc); +- +- g_Windowing.DisableGUIShader(); +- +- VerifyGLState(); +- +- glDisable(m_textureTarget); +- VerifyGLState(); +-#endif +-} +- + void CLinuxRendererGLES::RenderEglImage(int index, int field) + { + #if defined(HAS_LIBSTAGEFRIGHT) +@@ -1786,11 +1719,7 @@ void CLinuxRendererGLES::UploadYV12Texture(int source) + YUVFIELDS& fields = buf.fields; + + +-#if defined(HAVE_LIBOPENMAX) +- if (!(im->flags&IMAGE_FLAG_READY) || m_buffers[source].openMaxBuffer) +-#else + if (!(im->flags&IMAGE_FLAG_READY)) +-#endif + { + return; + } +@@ -2904,13 +2833,6 @@ unsigned int CLinuxRendererGLES::GetProcessorSize() + return 0; + } + +-#ifdef HAVE_LIBOPENMAX +-void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index) +-{ +- YUVBUFFER &buf = m_buffers[index]; +- buf.openMaxBuffer = picture->openMaxBuffer; +-} +-#endif + #ifdef HAVE_VIDEOTOOLBOXDECODER + void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + { +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index 1e89ecf..2cc5821 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -39,7 +39,7 @@ class CRenderCapture; + class CBaseTexture; + namespace Shaders { class BaseYUV2RGBShader; } + namespace Shaders { class BaseVideoFilterShader; } +-class COpenMaxVideo; ++class COpenMaxVideoBuffer; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; + typedef std::vector Features; +@@ -158,9 +158,6 @@ class CLinuxRendererGLES : public CBaseRenderer + + virtual std::vector SupportedFormats() { return m_formats; } + +-#ifdef HAVE_LIBOPENMAX +- virtual void AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index); +-#endif + #ifdef HAVE_VIDEOTOOLBOXDECODER + virtual void AddProcessor(struct __CVBuffer *cvBufferRef, int index); + #endif +@@ -280,9 +277,6 @@ class CLinuxRendererGLES : public CBaseRenderer + YV12Image image; + unsigned flipindex; /* used to decide if this has been uploaded */ + +-#ifdef HAVE_LIBOPENMAX +- OpenMaxVideoBuffer *openMaxBuffer; +-#endif + #ifdef HAVE_VIDEOTOOLBOXDECODER + struct __CVBuffer *cvBufferRef; + #endif +diff --git a/xbmc/cores/VideoRenderers/Makefile.in b/xbmc/cores/VideoRenderers/Makefile.in +index d964285..5b78852 100644 +--- a/xbmc/cores/VideoRenderers/Makefile.in ++++ b/xbmc/cores/VideoRenderers/Makefile.in +@@ -18,6 +18,7 @@ endif + ifeq (@USE_OPENGLES@,1) + SRCS += LinuxRendererGLES.cpp + SRCS += OverlayRendererGL.cpp ++SRCS += OMXRenderer.cpp + endif + + LIB = VideoRenderer.a +diff --git a/xbmc/cores/VideoRenderers/OMXRenderer.cpp b/xbmc/cores/VideoRenderers/OMXRenderer.cpp +new file mode 100644 +index 0000000..ceaec7a +--- /dev/null ++++ b/xbmc/cores/VideoRenderers/OMXRenderer.cpp +@@ -0,0 +1,784 @@ ++/* ++ * Copyright (C) 2005-2013 Team XBMC ++ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#ifdef TARGET_RASPBERRY_PI ++ ++#include "Util.h" ++#include "OMXRenderer.h" ++#include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h" ++#include "filesystem/File.h" ++#include "settings/AdvancedSettings.h" ++#include "settings/DisplaySettings.h" ++#include "settings/MediaSettings.h" ++#include "settings/Settings.h" ++#include "threads/SingleLock.h" ++#include "utils/log.h" ++#include "utils/MathUtils.h" ++#include "windowing/WindowingFactory.h" ++#include "cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h" ++#include "xbmc/Application.h" ++ ++#define CLASSNAME "COMXRenderer" ++ ++#ifdef _DEBUG ++#define OMX_DEBUG_VERBOSE ++#endif ++ ++static void vout_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) ++{ ++ mmal_buffer_header_release(buffer); ++} ++ ++void COMXRenderer::vout_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) ++{ ++ COpenMaxVideoBuffer *omvb = (COpenMaxVideoBuffer *)buffer->user_data; ++ ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p (%p), len %d cmd:%x", CLASSNAME, __func__, port, buffer, omvb, buffer->length, buffer->cmd); ++ #endif ++ ++ if (m_format == RENDER_FMT_OMXEGL) ++ { ++ #if defined(HAVE_LIBOPENMAX) ++ mmal_queue_put(m_release_queue, buffer); ++ #endif ++ } ++ else if (m_format == RENDER_FMT_YUV420P) ++ { ++ mmal_buffer_header_release(buffer); ++ } ++ else assert(0); ++} ++ ++static void vout_input_port_cb_static(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) ++{ ++ COMXRenderer *omx = reinterpret_cast(port->userdata); ++ omx->vout_input_port_cb(port, buffer); ++} ++ ++bool COMXRenderer::init_vout(MMAL_ES_FORMAT_T *format) ++{ ++ MMAL_STATUS_T status; ++ // todo: deinterlace ++ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ ++ /* Create video renderer */ ++ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &m_vout); ++ if(status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to create vout component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ m_vout->control->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ status = mmal_port_enable(m_vout->control, vout_control_port_cb); ++ if(status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable vout control port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ m_vout_input = m_vout->input[0]; ++ m_vout_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ mmal_format_full_copy(m_vout_input->format, format); ++ status = mmal_port_format_commit(m_vout_input); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to commit vout input format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ if (m_format == RENDER_FMT_YUV420P) ++ m_vout_input->buffer_num = m_NumYV12Buffers; ++ else ++ m_vout_input->buffer_num = m_vout_input->buffer_num_min; ++ m_vout_input->buffer_size = m_vout_input->buffer_size_recommended; ++ ++ status = mmal_port_enable(m_vout_input, vout_input_port_cb_static); ++ if(status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to vout enable input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ status = mmal_component_enable(m_vout); ++ if(status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable vout component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ if (m_format == RENDER_FMT_YUV420P) ++ { ++ m_vout_input_pool = mmal_pool_create(m_vout_input->buffer_num, m_vout_input->buffer_size); ++ if (!m_vout_input_pool) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to create pool for decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ } ++ return true; ++} ++ ++bool COMXRenderer::change_vout_input_format(MMAL_ES_FORMAT_T *format) ++{ ++ MMAL_STATUS_T status; ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ ++ status = mmal_port_disable(m_vout_input); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to disable vout input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ mmal_format_full_copy(m_vout_input->format, format); ++ status = mmal_port_format_commit(m_vout_input); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to commit vout input format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ m_vout_input->buffer_size = m_vout_input->buffer_size_min; ++ status = mmal_port_enable(m_vout_input, vout_input_port_cb_static); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable vout input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ return true; ++} ++ ++ ++static void *vout_worker(void *p) ++{ ++ MMAL_QUEUE_T *queue = (MMAL_QUEUE_T *)p; ++ ++ while (true) ++ { ++ MMAL_BUFFER_HEADER_T *buffer = mmal_queue_wait(queue); ++ COpenMaxVideoBuffer *omvb = (COpenMaxVideoBuffer *)buffer->user_data; ++ omvb->Release(); ++ } ++ return NULL; ++} ++ ++COMXRenderer::COMXRenderer() ++{ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ m_vout = NULL; ++ m_vout_input = NULL; ++ m_vout_input_pool = NULL; ++ memset(m_buffers, 0, sizeof m_buffers); ++ m_release_queue = mmal_queue_create(); ++ pthread_create(&m_worker, NULL, vout_worker, (void *)m_release_queue); ++} ++ ++COMXRenderer::~COMXRenderer() ++{ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ UnInit(); ++} ++ ++void COMXRenderer::AddProcessor(COpenMaxVideoBuffer *openMaxBuffer, int index) ++{ ++#if defined(HAVE_LIBOPENMAX) ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %p (%p) %i", CLASSNAME, __func__, openMaxBuffer, openMaxBuffer->mmal_buffer, index); ++#endif ++ ++ YUVBUFFER &buf = m_buffers[index]; ++ assert(!buf.openMaxBuffer); ++ memset(&buf, 0, sizeof buf); ++ buf.openMaxBuffer = openMaxBuffer->Acquire(); ++#endif ++} ++ ++bool COMXRenderer::Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation) ++{ ++ ReleaseBuffers(); ++ ++ m_sourceWidth = width; ++ m_sourceHeight = height; ++ m_renderOrientation = orientation; ++ ++ m_fps = fps; ++ m_iFlags = flags; ++ m_format = format; ++ ++ CLog::Log(LOGDEBUG, "%s::%s - %dx%d->%dx%d@%.2f flags:%x format:%d ext:%x orient:%d", CLASSNAME, __func__, width, height, d_width, d_height, fps, flags, format, extended_format, orientation); ++ ++ m_RenderUpdateCallBackFn = NULL; ++ m_RenderUpdateCallBackCtx = NULL; ++ if ((m_format == RENDER_FMT_BYPASS) && g_application.GetCurrentPlayer()) ++ { ++ m_renderFeatures.clear(); ++ m_scalingMethods.clear(); ++ m_deinterlaceModes.clear(); ++ m_deinterlaceMethods.clear(); ++ ++ if (m_RenderFeaturesCallBackFn) ++ { ++ (*m_RenderFeaturesCallBackFn)(m_RenderFeaturesCallBackCtx, m_renderFeatures); ++ // after setting up m_renderFeatures, we are done with the callback ++ m_RenderFeaturesCallBackFn = NULL; ++ m_RenderFeaturesCallBackCtx = NULL; ++ } ++ g_application.m_pPlayer->GetRenderFeatures(m_renderFeatures); ++ g_application.m_pPlayer->GetDeinterlaceMethods(m_deinterlaceMethods); ++ g_application.m_pPlayer->GetDeinterlaceModes(m_deinterlaceModes); ++ g_application.m_pPlayer->GetScalingMethods(m_scalingMethods); ++ } ++ ++ // calculate the input frame aspect ratio ++ CalculateFrameAspectRatio(d_width, d_height); ++ ChooseBestResolution(fps); ++ m_destWidth = g_graphicsContext.GetResInfo(m_resolution).iWidth; ++ m_destHeight = g_graphicsContext.GetResInfo(m_resolution).iHeight; ++ SetViewMode(CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode); ++ ManageDisplay(); ++ ++ m_bConfigured = true; ++ ++ return true; ++} ++ ++int COMXRenderer::GetImage(YV12Image *image, int source, bool readonly) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %p %d %d", CLASSNAME, __func__, image, source, readonly); ++#endif ++ if (!image) return -1; ++ ++ if( source < 0) ++ return -1; ++ ++ if (m_format == RENDER_FMT_OMXEGL) ++ { ++ } ++ else if (m_format == RENDER_FMT_YUV420P) ++ { ++ const int pitch = ALIGN_UP(m_sourceWidth, 32); ++ const int aligned_height = ALIGN_UP(m_sourceHeight, 16); ++ MMAL_BUFFER_HEADER_T *buffer = NULL; ++ if (!m_vout) ++ { ++ MMAL_ES_FORMAT_T *m_es_format = mmal_format_alloc(); ++ m_es_format->encoding = MMAL_ENCODING_I420; ++ m_es_format->type = MMAL_ES_TYPE_VIDEO; ++ m_es_format->es->video.width = pitch; ++ m_es_format->es->video.height = aligned_height; ++ m_es_format->es->video.crop.width = m_sourceWidth; ++ m_es_format->es->video.crop.height = m_sourceHeight; ++ ++ if (CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_BT709) ++ m_es_format->es->video.color_space = MMAL_COLOR_SPACE_ITUR_BT709; ++ else if (CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_BT601) ++ m_es_format->es->video.color_space = MMAL_COLOR_SPACE_ITUR_BT601; ++ else if (CONF_FLAGS_YUVCOEF_MASK(m_iFlags) == CONF_FLAGS_YUVCOEF_240M) ++ m_es_format->es->video.color_space = MMAL_COLOR_SPACE_SMPTE240M; ++ ++ if (!m_vout && init_vout(m_es_format)) ++ { ++ mmal_format_free(m_es_format); ++ return -1; ++ } ++ mmal_format_free(m_es_format); ++ } ++ ++ buffer = mmal_queue_timedwait(m_vout_input_pool->queue, 500); ++ if (!buffer) ++ { ++ CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__); ++ return -1; ++ } ++ ++ mmal_buffer_header_reset(buffer); ++ ++ buffer->length = 3 * pitch * aligned_height >> 1; ++ assert(buffer->length <= buffer->alloc_size); ++ ++ image->width = m_sourceWidth; ++ image->height = m_sourceHeight; ++ image->flags = 0; ++ image->cshift_x = 1; ++ image->cshift_y = 1; ++ image->bpp = 1; ++ ++ image->stride[0] = pitch; ++ image->stride[1] = image->stride[2] = pitch>>image->cshift_x; ++ ++ image->planesize[0] = pitch * aligned_height; ++ image->planesize[1] = image->planesize[2] = (pitch>>image->cshift_x)*(aligned_height>>image->cshift_y); ++ ++ image->plane[0] = (uint8_t *)buffer->data; ++ image->plane[1] = image->plane[0] + image->planesize[0]; ++ image->plane[2] = image->plane[1] + image->planesize[1]; ++ ++ CLog::Log(LOGDEBUG, "%s::%s - %p %d", CLASSNAME, __func__, buffer, source); ++ YUVBUFFER &buf = m_buffers[source]; ++ memset(&buf, 0, sizeof buf); ++ buf.mmal_buffer = buffer; ++ //return -1; ++ } ++ else assert(0); ++ ++ return source; ++} ++ ++void COMXRenderer::ReleaseBuffer(int idx) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %d", CLASSNAME, __func__, idx); ++#endif ++ YUVBUFFER &buf = m_buffers[idx]; ++ SAFE_RELEASE(buf.openMaxBuffer); ++} ++ ++void COMXRenderer::ReleaseImage(int source, bool preserve) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %d %d", CLASSNAME, __func__, source, preserve); ++#endif ++} ++ ++void COMXRenderer::Reset() ++{ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++} ++ ++void COMXRenderer::Flush() ++{ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++} ++ ++void COMXRenderer::Update() ++{ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ if (!m_bConfigured) return; ++ ManageDisplay(); ++} ++ ++void COMXRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %d %x %d", CLASSNAME, __func__, clear, flags, alpha); ++#endif ++ ++ if (!m_bConfigured) return; ++ ++ CSingleLock lock(g_graphicsContext); ++ ++ ManageDisplay(); ++ ++ // if running bypass, then the player might need the src/dst rects ++ // for sizing video playback on a layer other than the gles layer. ++ if (m_RenderUpdateCallBackFn) ++ (*m_RenderUpdateCallBackFn)(m_RenderUpdateCallBackCtx, m_sourceRect, m_destRect); ++ ++ SetVideoRect(m_sourceRect, m_destRect); ++ ++ CRect old = g_graphicsContext.GetScissors(); ++ ++ g_graphicsContext.BeginPaint(); ++ g_graphicsContext.SetScissors(m_destRect); ++ ++ glEnable(GL_BLEND); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ++ glClearColor(0, 0, 0, 0); ++ glClear(GL_COLOR_BUFFER_BIT); ++ ++ g_graphicsContext.SetScissors(old); ++ g_graphicsContext.EndPaint(); ++} ++ ++void COMXRenderer::FlipPage(int source) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %d", CLASSNAME, __func__, source); ++#endif ++ ++ if (!m_bConfigured || m_format == RENDER_FMT_BYPASS) ++ return; ++ ++ YUVBUFFER *buffer = &m_buffers[source]; ++ // we only want to upload frames once ++ if (buffer->flipindex++) ++ return; ++ if (m_format == RENDER_FMT_OMXEGL) ++ { ++ COpenMaxVideoBuffer *omvb = buffer->openMaxBuffer; ++ if (omvb) ++ { ++#if defined(HAVE_LIBOPENMAX) ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p (%p) frame:%d(%d)", CLASSNAME, __func__, omvb, omvb->mmal_buffer, m_changed_count_vout, omvb->m_changed_count); ++#endif ++ ++ ++ MMAL_ES_FORMAT_T *m_es_format = mmal_format_alloc(); ++ m_es_format->encoding = MMAL_ENCODING_OPAQUE; ++ m_es_format->type = MMAL_ES_TYPE_VIDEO; ++ m_es_format->es->video.width = m_sourceWidth; ++ m_es_format->es->video.height = m_sourceHeight; ++ m_es_format->es->video.crop.width = m_sourceWidth; ++ m_es_format->es->video.crop.height = m_sourceHeight; ++ ++ if (!m_vout && init_vout(m_es_format)) ++ { ++ mmal_format_free(m_es_format); ++ return; ++ } ++ mmal_format_free(m_es_format); ++ ++ /*if (m_changed_count_vout != omvb->m_changed_count) ++ { ++ CLog::Log(LOGDEBUG, "%s::%s format changed frame:%d(%d)", CLASSNAME, __func__, m_changed_count_vout, omvb->m_changed_count); ++ change_vout_input_format(omvb->GetFormat()); ++ m_changed_count_vout = omvb->m_changed_count; ++ }*/ ++ omvb->Acquire(); ++ mmal_port_send_buffer(m_vout_input, omvb->mmal_buffer); ++ } else assert(0); ++#endif ++ } ++ else if (m_format == RENDER_FMT_YUV420P) ++ { ++ CLog::Log(LOGDEBUG, "%s::%s - %p %d", CLASSNAME, __func__, buffer->mmal_buffer, source); ++ if (buffer->mmal_buffer) ++ mmal_port_send_buffer(m_vout_input, buffer->mmal_buffer); ++ else assert(0); ++ } ++ else assert(0); ++} ++ ++unsigned int COMXRenderer::PreInit() ++{ ++ CSingleLock lock(g_graphicsContext); ++ m_bConfigured = false; ++ UnInit(); ++ ++ m_changed_count_vout = 0; ++ ++ m_iFlags = 0; ++ m_src_rect.SetRect(0, 0, 0, 0); ++ m_dst_rect.SetRect(0, 0, 0, 0); ++ m_video_stereo_mode = RENDER_STEREO_MODE_OFF; ++ m_display_stereo_mode = RENDER_STEREO_MODE_OFF; ++ m_StereoInvert = false; ++ ++ m_resolution = CDisplaySettings::Get().GetCurrentResolution(); ++ if ( m_resolution == RES_WINDOW ) ++ m_resolution = RES_DESKTOP; ++ ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ ++ m_formats.clear(); ++ m_formats.push_back(RENDER_FMT_YUV420P); ++ m_formats.push_back(RENDER_FMT_OMXEGL); ++ m_formats.push_back(RENDER_FMT_BYPASS); ++ ++ m_NumYV12Buffers = 3; ++ ++ return 0; ++} ++ ++void COMXRenderer::ReleaseBuffers() ++{ ++#if defined(HAVE_LIBOPENMAX) ++ for (int i=0; icontrol); ++ } ++ ++ if (m_vout_input) ++ { ++ mmal_port_flush(m_vout_input); ++ mmal_port_disable(m_vout_input); ++ m_vout_input = NULL; ++ } ++ ++ if (m_vout_input_pool) ++ { ++ mmal_pool_destroy(m_vout_input_pool); ++ m_vout_input_pool = NULL; ++ } ++ ++ if (m_vout) ++ { ++ mmal_component_release(m_vout); ++ m_vout = NULL; ++ } ++ ReleaseBuffers(); ++ ++ m_RenderUpdateCallBackFn = NULL; ++ m_RenderUpdateCallBackCtx = NULL; ++ m_RenderFeaturesCallBackFn = NULL; ++ m_RenderFeaturesCallBackCtx = NULL; ++ ++ m_bConfigured = false; ++} ++ ++bool COMXRenderer::RenderCapture(CRenderCapture* capture) ++{ ++ if (!m_bConfigured) ++ return false; ++ ++ CLog::Log(LOGDEBUG, "%s::%s - %p", CLASSNAME, __func__, capture); ++ ++ capture->BeginRender(); ++ capture->EndRender(); ++ ++ return true; ++} ++ ++//******************************************************************************************************** ++// YV12 Texture creation, deletion, copying + clearing ++//******************************************************************************************************** ++ ++bool COMXRenderer::Supports(EDEINTERLACEMODE mode) ++{ ++ // Player controls render, let it dictate available deinterlace modes ++ if (m_format == RENDER_FMT_BYPASS) ++ { ++ Features::iterator itr = std::find(m_deinterlaceModes.begin(),m_deinterlaceModes.end(), mode); ++ return itr != m_deinterlaceModes.end(); ++ } ++ ++ if(mode == VS_DEINTERLACEMODE_OFF ++ || mode == VS_DEINTERLACEMODE_AUTO ++ || mode == VS_DEINTERLACEMODE_FORCE) ++ return true; ++ ++ return false; ++} ++ ++bool COMXRenderer::Supports(EINTERLACEMETHOD method) ++{ ++ // Player controls render, let it dictate available deinterlace methods ++ if (m_format == RENDER_FMT_BYPASS) ++ { ++ Features::iterator itr = std::find(m_deinterlaceMethods.begin(),m_deinterlaceMethods.end(), method); ++ return itr != m_deinterlaceMethods.end(); ++ } ++ ++ if (method == VS_INTERLACEMETHOD_DEINTERLACE_HALF) ++ return true; ++ ++ return false; ++} ++ ++bool COMXRenderer::Supports(ERENDERFEATURE feature) ++{ ++ // Player controls render, let it dictate available render features ++ if (m_format == RENDER_FMT_BYPASS) ++ { ++ Features::iterator itr = std::find(m_renderFeatures.begin(),m_renderFeatures.end(), feature); ++ return itr != m_renderFeatures.end(); ++ } ++ ++ if (feature == RENDERFEATURE_STRETCH || ++ feature == RENDERFEATURE_CROP || ++ feature == RENDERFEATURE_ZOOM || ++ feature == RENDERFEATURE_ROTATION || ++ feature == RENDERFEATURE_VERTICAL_SHIFT || ++ feature == RENDERFEATURE_PIXEL_RATIO) ++ return true; ++ ++ return false; ++} ++ ++bool COMXRenderer::Supports(ESCALINGMETHOD method) ++{ ++ // Player controls render, let it dictate available scaling methods ++ if (m_format == RENDER_FMT_BYPASS) ++ { ++ Features::iterator itr = std::find(m_scalingMethods.begin(),m_scalingMethods.end(), method); ++ return itr != m_scalingMethods.end(); ++ } ++ return false; ++} ++ ++EINTERLACEMETHOD COMXRenderer::AutoInterlaceMethod() ++{ ++ return VS_INTERLACEMETHOD_DEINTERLACE_HALF; ++} ++ ++unsigned int COMXRenderer::GetProcessorSize() ++{ ++ if (m_format == RENDER_FMT_OMXEGL) ++ return 1; ++ else ++ return 0; ++} ++ ++#endif ++ ++void COMXRenderer::SetVideoRect(const CRect& InSrcRect, const CRect& InDestRect) ++{ ++ // we get called twice a frame for left/right. Can ignore the rights. ++ if (g_graphicsContext.GetStereoView() == RENDER_STEREO_VIEW_RIGHT) ++ return; ++ ++ if (!m_vout) ++ return; ++ ++ CRect SrcRect = InSrcRect, DestRect = InDestRect; ++ RENDER_STEREO_MODE video_stereo_mode = (m_iFlags & CONF_FLAGS_STEREO_MODE_SBS) ? RENDER_STEREO_MODE_SPLIT_VERTICAL : ++ (m_iFlags & CONF_FLAGS_STEREO_MODE_TAB) ? RENDER_STEREO_MODE_SPLIT_HORIZONTAL : RENDER_STEREO_MODE_OFF; ++ bool stereo_invert = (m_iFlags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false; ++ RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode(); ++ ++ // fix up transposed video ++ if (m_renderOrientation == 90 || m_renderOrientation == 270) ++ { ++ float diff = (DestRect.Height() - DestRect.Width()) * 0.5f; ++ DestRect.x1 -= diff; ++ DestRect.x2 += diff; ++ DestRect.y1 += diff; ++ DestRect.y2 -= diff; ++ } ++ ++ // check if destination rect or video view mode has changed ++ if (!(m_dst_rect != DestRect) && !(m_src_rect != SrcRect) && m_video_stereo_mode == video_stereo_mode && m_display_stereo_mode == display_stereo_mode && m_StereoInvert == stereo_invert) ++ return; ++ ++ CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d (o:%d v:%d d:%d i:%d)", CLASSNAME, __func__, ++ (int)SrcRect.x1, (int)SrcRect.y1, (int)SrcRect.x2, (int)SrcRect.y2, ++ (int)DestRect.x1, (int)DestRect.y1, (int)DestRect.x2, (int)DestRect.y2, ++ m_renderOrientation, video_stereo_mode, display_stereo_mode, stereo_invert); ++ ++ m_src_rect = SrcRect; ++ m_dst_rect = DestRect; ++ m_video_stereo_mode = video_stereo_mode; ++ m_display_stereo_mode = display_stereo_mode; ++ m_StereoInvert = stereo_invert; ++ ++ // might need to scale up m_dst_rect to display size as video decodes ++ // to separate video plane that is at display size. ++ RESOLUTION res = g_graphicsContext.GetVideoResolution(); ++ CRect gui(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight); ++ CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight); ++ ++ if (display_stereo_mode != RENDER_STEREO_MODE_OFF && display_stereo_mode != RENDER_STEREO_MODE_MONO) ++ switch (video_stereo_mode) ++ { ++ case RENDER_STEREO_MODE_SPLIT_VERTICAL: ++ // optimisation - use simpler display mode in common case of unscaled 3d with same display mode ++ if (video_stereo_mode == display_stereo_mode && DestRect.x1 == 0.0f && DestRect.x2 * 2.0f == gui.Width() && !stereo_invert) ++ { ++ SrcRect.x2 *= 2.0f; ++ DestRect.x2 *= 2.0f; ++ video_stereo_mode = RENDER_STEREO_MODE_OFF; ++ display_stereo_mode = RENDER_STEREO_MODE_OFF; ++ } ++ else if (display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) ++ { ++ SrcRect.x2 *= 2.0f; ++ } ++ break; ++ ++ case RENDER_STEREO_MODE_SPLIT_HORIZONTAL: ++ // optimisation - use simpler display mode in common case of unscaled 3d with same display mode ++ if (video_stereo_mode == display_stereo_mode && DestRect.y1 == 0.0f && DestRect.y2 * 2.0f == gui.Height() && !stereo_invert) ++ { ++ SrcRect.y2 *= 2.0f; ++ DestRect.y2 *= 2.0f; ++ video_stereo_mode = RENDER_STEREO_MODE_OFF; ++ display_stereo_mode = RENDER_STEREO_MODE_OFF; ++ } ++ else if (display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) ++ { ++ SrcRect.y2 *= 2.0f; ++ } ++ break; ++ ++ default: break; ++ } ++ ++ if (gui != display) ++ { ++ float xscale = display.Width() / gui.Width(); ++ float yscale = display.Height() / gui.Height(); ++ DestRect.x1 *= xscale; ++ DestRect.x2 *= xscale; ++ DestRect.y1 *= yscale; ++ DestRect.y2 *= yscale; ++ } ++ ++ MMAL_DISPLAYREGION_T region; ++ memset(®ion, 0, sizeof region); ++ ++ region.set = MMAL_DISPLAY_SET_DEST_RECT|MMAL_DISPLAY_SET_SRC_RECT|MMAL_DISPLAY_SET_FULLSCREEN|MMAL_DISPLAY_SET_NOASPECT|MMAL_DISPLAY_SET_MODE; ++ region.dest_rect.x = lrintf(DestRect.x1); ++ region.dest_rect.y = lrintf(DestRect.y1); ++ region.dest_rect.width = lrintf(DestRect.Width()); ++ region.dest_rect.height = lrintf(DestRect.Height()); ++ ++ region.src_rect.x = lrintf(SrcRect.x1); ++ region.src_rect.y = lrintf(SrcRect.y1); ++ region.src_rect.width = lrintf(SrcRect.Width()); ++ region.src_rect.height = lrintf(SrcRect.Height()); ++ ++ region.fullscreen = MMAL_FALSE; ++ region.noaspect = MMAL_TRUE; ++ ++ if (m_renderOrientation) ++ { ++ region.set |= MMAL_DISPLAY_SET_TRANSFORM; ++ if (m_renderOrientation == 90) ++ region.transform = MMAL_DISPLAY_ROT90; ++ else if (m_renderOrientation == 180) ++ region.transform = MMAL_DISPLAY_ROT180; ++ else if (m_renderOrientation == 270) ++ region.transform = MMAL_DISPLAY_ROT270; ++ else assert(0); ++ } ++ ++ if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) ++ region.mode = MMAL_DISPLAY_MODE_STEREO_TOP_TO_TOP; ++ else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) ++ region.mode = MMAL_DISPLAY_MODE_STEREO_TOP_TO_LEFT; ++ else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) ++ region.mode = MMAL_DISPLAY_MODE_STEREO_LEFT_TO_TOP; ++ else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) ++ region.mode = MMAL_DISPLAY_MODE_STEREO_LEFT_TO_LEFT; ++ else ++ region.mode = MMAL_DISPLAY_MODE_LETTERBOX; ++ ++ MMAL_STATUS_T status = mmal_util_set_display_region(m_vout_input, ®ion); ++ if (status != MMAL_SUCCESS) ++ CLog::Log(LOGERROR, "%s::%s Failed to set display region (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ ++ CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d mode:%d", CLASSNAME, __func__, ++ region.src_rect.x, region.src_rect.y, region.src_rect.width, region.src_rect.height, ++ region.dest_rect.x, region.dest_rect.y, region.dest_rect.width, region.dest_rect.height, region.mode); ++} +diff --git a/xbmc/cores/VideoRenderers/OMXRenderer.h b/xbmc/cores/VideoRenderers/OMXRenderer.h +new file mode 100644 +index 0000000..724342a +--- /dev/null ++++ b/xbmc/cores/VideoRenderers/OMXRenderer.h +@@ -0,0 +1,129 @@ ++#pragma once ++ ++/* ++ * Copyright (C) 2005-2013 Team XBMC ++ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#if defined(TARGET_RASPBERRY_PI) ++ ++#include "guilib/GraphicContext.h" ++#include "RenderFlags.h" ++#include "RenderFormats.h" ++#include "BaseRenderer.h" ++#include "RenderCapture.h" ++#include "settings/VideoSettings.h" ++#include "cores/dvdplayer/DVDStreamInfo.h" ++#include "guilib/Geometry.h" ++ ++#include ++#include ++#include ++#include ++ ++#define AUTOSOURCE -1 ++ ++class CBaseTexture; ++class COpenMaxVideoBuffer; ++ ++struct DVDVideoPicture; ++ ++class COMXRenderer : public CBaseRenderer ++{ ++ struct YUVBUFFER ++ { ++ COpenMaxVideoBuffer *openMaxBuffer; // used for hw decoded buffers ++ MMAL_BUFFER_HEADER_T *mmal_buffer; // used for sw decoded buffers ++ unsigned flipindex; /* used to decide if this has been uploaded */ ++ }; ++public: ++ COMXRenderer(); ++ ~COMXRenderer(); ++ ++ virtual void Update(); ++ virtual void SetupScreenshot() {}; ++ ++ bool RenderCapture(CRenderCapture* capture); ++ ++ // Player functions ++ virtual bool Configure(unsigned int width, unsigned int height, unsigned int d_width, unsigned int d_height, float fps, unsigned flags, ERenderFormat format, unsigned extended_format, unsigned int orientation); ++ virtual int GetImage(YV12Image *image, int source = AUTOSOURCE, bool readonly = false); ++ virtual void ReleaseImage(int source, bool preserve = false); ++ virtual void ReleaseBuffer(int idx); ++ virtual void FlipPage(int source); ++ virtual unsigned int PreInit(); ++ virtual void UnInit(); ++ virtual void Reset(); /* resets renderer after seek for example */ ++ virtual void Flush(); ++ virtual bool IsConfigured() { return m_bConfigured; } ++ virtual void AddProcessor(COpenMaxVideoBuffer *openMaxVideoBuffer, int index); ++ virtual std::vector SupportedFormats() { return m_formats; } ++ ++ virtual bool Supports(ERENDERFEATURE feature); ++ virtual bool Supports(EDEINTERLACEMODE mode); ++ virtual bool Supports(EINTERLACEMETHOD method); ++ virtual bool Supports(ESCALINGMETHOD method); ++ ++ virtual EINTERLACEMETHOD AutoInterlaceMethod(); ++ ++ void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); ++ ++ virtual void SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } ++ virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } ++ virtual unsigned int GetProcessorSize(); ++ virtual void SetVideoRect(const CRect& SrcRect, const CRect& DestRect); ++ ++ void vout_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); ++protected: ++ int m_NumYV12Buffers; ++ ++ std::vector m_formats; ++ ++ YUVBUFFER m_buffers[NUM_BUFFERS]; ++ bool m_bConfigured; ++ unsigned int m_extended_format; ++ unsigned int m_destWidth; ++ unsigned int m_destHeight; ++ int m_neededBuffers; ++ ++ Features m_renderFeatures; ++ Features m_deinterlaceMethods; ++ Features m_deinterlaceModes; ++ Features m_scalingMethods; ++ ++ CRect m_src_rect; ++ CRect m_dst_rect; ++ RENDER_STEREO_MODE m_video_stereo_mode; ++ RENDER_STEREO_MODE m_display_stereo_mode; ++ bool m_StereoInvert; ++ ++ MMAL_COMPONENT_T *m_vout; ++ MMAL_PORT_T *m_vout_input; ++ MMAL_POOL_T *m_vout_input_pool; ++ ++ uint32_t m_changed_count_vout; ++ pthread_t m_worker; ++ MMAL_QUEUE_T *m_release_queue; ++ bool change_vout_input_format(MMAL_ES_FORMAT_T *m_format); ++ bool init_vout(MMAL_ES_FORMAT_T *m_format); ++ void ReleaseBuffers(); ++}; ++ ++#else ++#include "LinuxRenderer.h" ++#endif +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 568c8b2..f770146 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -41,6 +41,8 @@ + + #if defined(HAS_GL) + #include "LinuxRendererGL.h" ++#elif defined(TARGET_RASPBERRY_PI) ++ #include "OMXRenderer.h" + #elif HAS_GLES == 2 + #include "LinuxRendererGLES.h" + #elif defined(HAS_DX) +@@ -424,6 +426,8 @@ unsigned int CXBMCRenderManager::PreInit() + { + #if defined(HAS_GL) + m_pRenderer = new CLinuxRendererGL(); ++#elif defined(TARGET_RASPBERRY_PI) ++ m_pRenderer = new COMXRenderer(); + #elif HAS_GLES == 2 + m_pRenderer = new CLinuxRendererGLES(); + #elif defined(HAS_DX) +@@ -921,7 +925,7 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + #endif + #ifdef HAVE_LIBOPENMAX + else if(pic.format == RENDER_FMT_OMXEGL) +- m_pRenderer->AddProcessor(pic.openMax, &pic, index); ++ m_pRenderer->AddProcessor(pic.openMaxBuffer, index); + #endif + #ifdef TARGET_DARWIN + else if(pic.format == RENDER_FMT_CVBREF) +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index e8d4ca2..1b54c79 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -42,6 +42,7 @@ struct DVDVideoPicture; + #define ERRORBUFFSIZE 30 + + class CWinRenderer; ++class COMXRenderer; + class CLinuxRenderer; + class CLinuxRendererGL; + class CLinuxRendererGLES; +@@ -146,6 +147,8 @@ class CXBMCRenderManager + + #ifdef HAS_GL + CLinuxRendererGL *m_pRenderer; ++#elif defined(TARGET_RASPBERRY_PI) ++ COMXRenderer *m_pRenderer; + #elif HAS_GLES == 2 + CLinuxRendererGLES *m_pRenderer; + #elif defined(HAS_DX) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +index f8a5635..3a11154 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +@@ -191,6 +191,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne + #endif + CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str()); + ++#if defined(HAVE_LIBOPENMAX) ++ // libopenmax can handle dvd playback including stills ++ if (!CSettings::Get().GetBool("videoplayer.useomx")) ++#endif + if (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO)) + { + // If dvd is an mpeg2 and hint.stills +@@ -252,7 +256,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne + #if defined(HAVE_LIBOPENMAX) + if (CSettings::Get().GetBool("videoplayer.useomx") && !hint.software ) + { +- if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_VC1) ++ if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_H263 || hint.codec == AV_CODEC_ID_MPEG4 || ++ hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO || ++ hint.codec == AV_CODEC_ID_VP6 || hint.codec == AV_CODEC_ID_VP6F || hint.codec == AV_CODEC_ID_VP6A || hint.codec == AV_CODEC_ID_VP8 || ++ hint.codec == AV_CODEC_ID_THEORA || hint.codec == AV_CODEC_ID_MJPEG || hint.codec == AV_CODEC_ID_MJPEGB || hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) + { + if ( (pCodec = OpenCodec(new CDVDVideoCodecOpenMax(), hint, options)) ) return pCodec; + } +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index b236ad7..10b38d4 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -50,9 +50,7 @@ struct DVDCodecAvailableType + namespace DXVA { class CSurfaceContext; } + namespace VAAPI { class CVaapiRenderPicture; } + namespace VDPAU { class CVdpauRenderPicture; } +-class COpenMax; +-class COpenMaxVideo; +-struct OpenMaxVideoBuffer; ++class COpenMaxVideoBuffer; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; + class CDVDVideoCodecIMXBuffer; +@@ -82,8 +80,7 @@ struct DVDVideoPicture + }; + + struct { +- COpenMax *openMax; +- OpenMaxVideoBuffer *openMaxBuffer; ++ COpenMaxVideoBuffer *openMaxBuffer; + }; + + struct { +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp +index b2e7816..8323497 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp +@@ -28,114 +28,37 @@ + #include "DVDClock.h" + #include "DVDStreamInfo.h" + #include "DVDVideoCodecOpenMax.h" +-#include "OpenMaxVideo.h" ++#include "settings/Settings.h" + #include "utils/log.h" + +-#define CLASSNAME "COpenMax" ++#define CLASSNAME "CDVDVideoCodecOpenMax" + //////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////// +-CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() : CDVDVideoCodec() ++CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() ++ : m_omx_decoder( new COpenMaxVideo ) + { +- m_omx_decoder = NULL; +- m_pFormatName = "omx-xxxx"; +- +- m_convert_bitstream = false; +- memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); ++ CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this); + } + + CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax() + { ++ CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this); + Dispose(); + } + + bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + { +- // we always qualify even if DVDFactoryCodec does this too. +- if (CSettings::Get().GetBool("videoplayer.useomx") && !hints.software) +- { +- m_convert_bitstream = false; +- +- switch (hints.codec) +- { +- case AV_CODEC_ID_H264: +- { +- m_pFormatName = "omx-h264"; +- if (hints.extrasize < 7 || hints.extradata == NULL) +- { +- CLog::Log(LOGNOTICE, +- "%s::%s - avcC data too small or missing", CLASSNAME, __func__); +- return false; +- } +- // valid avcC data (bitstream) always starts with the value 1 (version) +- if ( *(char*)hints.extradata == 1 ) +- m_convert_bitstream = bitstream_convert_init(hints.extradata, hints.extrasize); +- } +- break; +- case AV_CODEC_ID_MPEG4: +- m_pFormatName = "omx-mpeg4"; +- break; +- case AV_CODEC_ID_MPEG2VIDEO: +- m_pFormatName = "omx-mpeg2"; +- break; +- case AV_CODEC_ID_VC1: +- m_pFormatName = "omx-vc1"; +- break; +- default: +- return false; +- break; +- } +- +- m_omx_decoder = new COpenMaxVideo; +- if (!m_omx_decoder->Open(hints)) +- { +- CLog::Log(LOGERROR, +- "%s::%s - failed to open, codec(%d), profile(%d), level(%d)", +- CLASSNAME, __func__, hints.codec, hints.profile, hints.level); +- return false; +- } +- +- // allocate a YV12 DVDVideoPicture buffer. +- // first make sure all properties are reset. +- memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); +- +- m_videobuffer.dts = DVD_NOPTS_VALUE; +- m_videobuffer.pts = DVD_NOPTS_VALUE; +- //m_videobuffer.format = RENDER_FMT_YUV420P; +- m_videobuffer.format = RENDER_FMT_OMXEGL; +- m_videobuffer.color_range = 0; +- m_videobuffer.color_matrix = 4; +- m_videobuffer.iFlags = DVP_FLAG_ALLOCATED; +- m_videobuffer.iWidth = hints.width; +- m_videobuffer.iHeight = hints.height; +- m_videobuffer.iDisplayWidth = hints.width; +- m_videobuffer.iDisplayHeight = hints.height; +- +- return true; +- } ++ return m_omx_decoder->Open(hints, options, m_omx_decoder); ++} + +- return false; ++const char* CDVDVideoCodecOpenMax::GetName(void) ++{ ++ return m_omx_decoder ? m_omx_decoder->GetName() : "omx-xxx"; + } + + void CDVDVideoCodecOpenMax::Dispose() + { +- if (m_omx_decoder) +- { +- m_omx_decoder->Close(); +- delete m_omx_decoder; +- m_omx_decoder = NULL; +- } +- if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED) +- { +- m_videobuffer.iFlags = 0; +- } +- if (m_convert_bitstream) +- { +- if (m_sps_pps_context.sps_pps_data) +- { +- free(m_sps_pps_context.sps_pps_data); +- m_sps_pps_context.sps_pps_data = NULL; +- } +- } ++ m_omx_decoder->Dispose(); + } + + void CDVDVideoCodecOpenMax::SetDropState(bool bDrop) +@@ -145,37 +68,12 @@ void CDVDVideoCodecOpenMax::SetDropState(bool bDrop) + + int CDVDVideoCodecOpenMax::Decode(uint8_t* pData, int iSize, double dts, double pts) + { +- if (pData) +- { +- int rtn; +- int demuxer_bytes = iSize; +- uint8_t *demuxer_content = pData; +- bool bitstream_convered = false; +- +- if (m_convert_bitstream) +- { +- // convert demuxer packet from bitstream to bytestream (AnnexB) +- int bytestream_size = 0; +- uint8_t *bytestream_buff = NULL; +- +- bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size); +- if (bytestream_buff && (bytestream_size > 0)) +- { +- bitstream_convered = true; +- demuxer_bytes = bytestream_size; +- demuxer_content = bytestream_buff; +- } +- } +- +- rtn = m_omx_decoder->Decode(demuxer_content, demuxer_bytes, dts, pts); +- +- if (bitstream_convered) +- free(demuxer_content); ++ return m_omx_decoder->Decode(pData, iSize, dts, pts); ++} + +- return rtn; +- } +- +- return VC_BUFFER; ++unsigned CDVDVideoCodecOpenMax::GetAllowedReferences() ++{ ++ return m_omx_decoder->GetAllowedReferences(); + } + + void CDVDVideoCodecOpenMax::Reset(void) +@@ -185,172 +83,17 @@ void CDVDVideoCodecOpenMax::Reset(void) + + bool CDVDVideoCodecOpenMax::GetPicture(DVDVideoPicture* pDvdVideoPicture) + { +- m_omx_decoder->GetPicture(&m_videobuffer); +- *pDvdVideoPicture = m_videobuffer; +- +- return VC_PICTURE | VC_BUFFER; +-} +- +-//////////////////////////////////////////////////////////////////////////////////////////// +-bool CDVDVideoCodecOpenMax::bitstream_convert_init(void *in_extradata, int in_extrasize) +-{ +- // based on h264_mp4toannexb_bsf.c (ffmpeg) +- // which is Copyright (c) 2007 Benoit Fouet +- // and Licensed GPL 2.1 or greater +- +- m_sps_pps_size = 0; +- m_sps_pps_context.sps_pps_data = NULL; +- +- // nothing to filter +- if (!in_extradata || in_extrasize < 6) +- return false; +- +- uint16_t unit_size; +- uint32_t total_size = 0; +- uint8_t *out = NULL, unit_nb, sps_done = 0; +- const uint8_t *extradata = (uint8_t*)in_extradata + 4; +- static const uint8_t nalu_header[4] = {0, 0, 0, 1}; +- +- // retrieve length coded size +- m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1; +- if (m_sps_pps_context.length_size == 3) +- return false; +- +- // retrieve sps and pps unit(s) +- unit_nb = *extradata++ & 0x1f; // number of sps unit(s) +- if (!unit_nb) +- { +- unit_nb = *extradata++; // number of pps unit(s) +- sps_done++; +- } +- while (unit_nb--) +- { +- unit_size = extradata[0] << 8 | extradata[1]; +- total_size += unit_size + 4; +- if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) ) +- { +- free(out); +- return false; +- } +- uint8_t* new_out = (uint8_t*)realloc(out, total_size); +- if (new_out) +- { +- out = new_out; +- } +- else +- { +- CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out", __FUNCTION__); +- free(out); +- return false; +- } +- +- memcpy(out + total_size - unit_size - 4, nalu_header, 4); +- memcpy(out + total_size - unit_size, extradata + 2, unit_size); +- extradata += 2 + unit_size; +- +- if (!unit_nb && !sps_done++) +- unit_nb = *extradata++; // number of pps unit(s) +- } +- +- m_sps_pps_context.sps_pps_data = out; +- m_sps_pps_context.size = total_size; +- m_sps_pps_context.first_idr = 1; +- +- return true; ++ return m_omx_decoder->GetPicture(pDvdVideoPicture); + } + +-bool CDVDVideoCodecOpenMax::bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size) ++bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture) + { +- // based on h264_mp4toannexb_bsf.c (ffmpeg) +- // which is Copyright (c) 2007 Benoit Fouet +- // and Licensed GPL 2.1 or greater +- +- uint8_t *buf = pData; +- uint32_t buf_size = iSize; +- uint8_t unit_type; +- int32_t nal_size; +- uint32_t cumul_size = 0; +- const uint8_t *buf_end = buf + buf_size; +- +- do +- { +- if (buf + m_sps_pps_context.length_size > buf_end) +- goto fail; +- +- if (m_sps_pps_context.length_size == 1) +- nal_size = buf[0]; +- else if (m_sps_pps_context.length_size == 2) +- nal_size = buf[0] << 8 | buf[1]; +- else +- nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +- +- buf += m_sps_pps_context.length_size; +- unit_type = *buf & 0x1f; +- +- if (buf + nal_size > buf_end || nal_size < 0) +- goto fail; +- +- // prepend only to the first type 5 NAL unit of an IDR picture +- if (m_sps_pps_context.first_idr && unit_type == 5) +- { +- bitstream_alloc_and_copy(poutbuf, poutbuf_size, +- m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size); +- m_sps_pps_context.first_idr = 0; +- } +- else +- { +- bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size); +- if (!m_sps_pps_context.first_idr && unit_type == 1) +- m_sps_pps_context.first_idr = 1; +- } +- +- buf += nal_size; +- cumul_size += nal_size + m_sps_pps_context.length_size; +- } while (cumul_size < buf_size); +- +- return true; +- +-fail: +- free(*poutbuf); +- *poutbuf = NULL; +- *poutbuf_size = 0; +- return false; ++ return m_omx_decoder->ClearPicture(pDvdVideoPicture); + } + +-void CDVDVideoCodecOpenMax::bitstream_alloc_and_copy( +- uint8_t **poutbuf, int *poutbuf_size, +- const uint8_t *sps_pps, uint32_t sps_pps_size, +- const uint8_t *in, uint32_t in_size) ++bool CDVDVideoCodecOpenMax::GetCodecStats(double &pts, int &droppedPics) + { +- // based on h264_mp4toannexb_bsf.c (ffmpeg) +- // which is Copyright (c) 2007 Benoit Fouet +- // and Licensed GPL 2.1 or greater +- +- #define CHD_WB32(p, d) { \ +- ((uint8_t*)(p))[3] = (d); \ +- ((uint8_t*)(p))[2] = (d) >> 8; \ +- ((uint8_t*)(p))[1] = (d) >> 16; \ +- ((uint8_t*)(p))[0] = (d) >> 24; } +- +- uint32_t offset = *poutbuf_size; +- uint8_t nal_header_size = offset ? 3 : 4; +- +- *poutbuf_size += sps_pps_size + in_size + nal_header_size; +- *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size); +- if (sps_pps) +- memcpy(*poutbuf + offset, sps_pps, sps_pps_size); +- +- memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); +- if (!offset) +- { +- CHD_WB32(*poutbuf + sps_pps_size, 1); +- } +- else +- { +- (*poutbuf + offset + sps_pps_size)[0] = 0; +- (*poutbuf + offset + sps_pps_size)[1] = 0; +- (*poutbuf + offset + sps_pps_size)[2] = 1; +- } ++ return m_omx_decoder->GetCodecStats(pts, droppedPics); + } + #endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -index b7c0c1b..4f243df 100644 +index fb80d02..4f243df 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h -@@ -41,6 +41,7 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec - virtual unsigned GetAllowedReferences(); +@@ -22,8 +22,9 @@ + #if defined(HAVE_LIBOPENMAX) + + #include "DVDVideoCodec.h" ++#include "OpenMaxVideo.h" + +-class COpenVideoMax; ++class COpenMaxVideo; + class CDVDVideoCodecOpenMax : public CDVDVideoCodec + { + public: +@@ -36,39 +37,14 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec + virtual int Decode(uint8_t *pData, int iSize, double dts, double pts); + virtual void Reset(void); + virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture); ++ virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); ++ virtual unsigned GetAllowedReferences(); virtual void SetDropState(bool bDrop); - virtual const char* GetName(void); +- virtual const char* GetName(void) { return (const char*)m_pFormatName; } ++ virtual const char* GetName(void); + virtual bool GetCodecStats(double &pts, int &droppedPics); protected: - OpenMaxVideoPtr m_omx_decoder; +- const char *m_pFormatName; +- COpenMaxVideo *m_omx_decoder; +- DVDVideoPicture m_videobuffer; +- +- // bitstream to bytestream (Annex B) conversion support. +- bool bitstream_convert_init(void *in_extradata, int in_extrasize); +- bool bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size); +- static void bitstream_alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size, +- const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size); +- +- typedef struct omx_bitstream_ctx { +- uint8_t length_size; +- uint8_t first_idr; +- uint8_t *sps_pps_data; +- uint32_t size; +- +- omx_bitstream_ctx() +- { +- length_size = 0; +- first_idr = 0; +- sps_pps_data = NULL; +- size = 0; +- } +- +- } omx_bitstream_ctx; +- +- uint32_t m_sps_pps_size; +- omx_bitstream_ctx m_sps_pps_context; +- bool m_convert_bitstream; ++ OpenMaxVideoPtr m_omx_decoder; + }; + + #endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +index 50dc8b7..b4ae0bb 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +@@ -16,7 +16,6 @@ SRCS += DVDVideoCodecVDA.cpp + SRCS += VDA.cpp + endif + ifeq (@USE_OPENMAX@,1) +-SRCS += OpenMax.cpp + SRCS += OpenMaxVideo.cpp + SRCS += DVDVideoCodecOpenMax.cpp + endif diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index 71d19af..612ae21 100644 +index dcbdb1e..3218b63 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -37,6 +37,7 @@ +@@ -32,1019 +32,1068 @@ + #include "DVDVideoCodec.h" + #include "utils/log.h" + #include "utils/TimeUtils.h" ++#include "settings/Settings.h" ++#include "settings/MediaSettings.h" #include "ApplicationMessenger.h" #include "Application.h" - #include "threads/Atomics.h" ++#include "threads/Atomics.h" +#include "guilib/GUIWindowManager.h" ++#include "cores/VideoRenderers/RenderFlags.h" ++#include "settings/DisplaySettings.h" ++#include "cores/VideoRenderers/RenderManager.h" - #include - #include -@@ -57,6 +58,7 @@ +-#include +-#include +-#include +-#include ++#include "linux/RBP.h" - #define OMX_BUFFERFLAG_PTS_INVALID (1<<28) - #define OMX_BUFFERFLAG_DROPPED (1<<29) -+#define OMX_BUFFERFLAG_FIRST_FIELD (1<<30) ++#define DTS_QUEUE - COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv) - : m_omv(omv), m_refs(0) -@@ -139,8 +141,11 @@ COpenMaxVideo::COpenMaxVideo() +-#define CLASSNAME "COpenMaxVideo" ++#ifdef _DEBUG ++#define OMX_DEBUG_VERBOSE ++#endif - m_deinterlace = false; - m_deinterlace_request = VS_DEINTERLACEMODE_OFF; -- m_deinterlace_second_field = false; - m_startframe = false; +-// TODO: These are Nvidia Tegra2 dependent, need to dynamiclly find the +-// right codec matched to video format. +-#define OMX_H264BASE_DECODER "OMX.Nvidia.h264.decode" +-// OMX.Nvidia.h264ext.decode segfaults, not sure why. +-//#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264ext.decode" +-#define OMX_H264MAIN_DECODER "OMX.Nvidia.h264.decode" +-#define OMX_H264HIGH_DECODER "OMX.Nvidia.h264ext.decode" +-#define OMX_MPEG4_DECODER "OMX.Nvidia.mp4.decode" +-#define OMX_MPEG4EXT_DECODER "OMX.Nvidia.mp4ext.decode" +-#define OMX_MPEG2V_DECODER "OMX.Nvidia.mpeg2v.decode" +-#define OMX_VC1_DECODER "OMX.Nvidia.vc1.decode" +- +-// EGL extension functions +-static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; +-static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; +-#define GETEXTENSION(type, ext) \ +-do \ +-{ \ +- ext = (type) eglGetProcAddress(#ext); \ +- if (!ext) \ +- { \ +- CLog::Log(LOGERROR, "%s::%s - ERROR getting proc addr of " #ext "\n", CLASSNAME, __func__); \ +- } \ +-} while (0); +- +-#define OMX_INIT_STRUCTURE(a) \ +- memset(&(a), 0, sizeof(a)); \ +- (a).nSize = sizeof(a); \ +- (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \ +- (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \ +- (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \ +- (a).nVersion.s.nStep = OMX_VERSION_STEP ++#define CLASSNAME "COpenMaxVideoBuffer" + ++COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv) ++ : m_omv(omv), m_refs(0) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); ++#endif ++ mmal_buffer = NULL; ++ width = 0; ++ height = 0; ++ index = 0; ++ m_aspect_ratio = 0.0f; ++ m_changed_count = 0; ++ dts = DVD_NOPTS_VALUE; ++} + +-COpenMaxVideo::COpenMaxVideo() ++COpenMaxVideoBuffer::~COpenMaxVideoBuffer() ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); ++#endif ++} ++ ++ ++COpenMaxVideoBuffer* COpenMaxVideoBuffer::Acquire() + { +- m_portChanging = false; ++ long count = AtomicIncrement(&m_refs); ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p (%p) ref:%ld", CLASSNAME, __func__, this, mmal_buffer, count); ++ #endif ++ (void)count; ++ return this; ++} + +- pthread_mutex_init(&m_omx_input_mutex, NULL); ++long COpenMaxVideoBuffer::Release() ++{ ++ long count = AtomicDecrement(&m_refs); ++#if defined(OMX_DEBUG_VERBOSE) ++CLog::Log(LOGDEBUG, "%s::%s %p (%p) ref:%ld", CLASSNAME, __func__, this, mmal_buffer, count); ++#endif ++ if (count == 0) ++ { ++ m_omv->ReleaseOpenMaxBuffer(this); ++ } ++ return count; ++} ++ ++#undef CLASSNAME ++#define CLASSNAME "COpenMaxVideo" ++ ++COpenMaxVideo::COpenMaxVideo() ++{ ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); ++ #endif + pthread_mutex_init(&m_omx_output_mutex, NULL); + +- m_omx_decoder_state_change = (sem_t*)malloc(sizeof(sem_t)); +- sem_init(m_omx_decoder_state_change, 0, 0); +- memset(&m_videobuffer, 0, sizeof(DVDVideoPicture)); + m_drop_state = false; + m_decoded_width = 0; + m_decoded_height = 0; +- m_omx_input_eos = false; +- m_omx_input_port = 0; +- m_omx_output_eos = false; +- m_omx_output_port = 0; +- m_videoplayback_done = false; ++ ++ m_finished = false; ++ m_pFormatName = "mmal-xxxx"; ++ ++ //m_interlace_mode = MMAL_InterlaceProgressive; ++ m_startframe = false; + m_decoderPts = DVD_NOPTS_VALUE; + m_droppedPics = 0; + m_decode_frame_number = 1; -+ m_skipDeinterlaceFields = false; ++ ++ m_dec = NULL; ++ m_dec_input = NULL; ++ m_dec_output = NULL; ++ m_dec_input_pool = NULL; ++ m_dec_output_pool = NULL; ++ ++ m_deint = NULL; ++ m_deint_connection = NULL; ++ ++ m_codingType = 0; ++ ++ m_changed_count = 0; ++ m_changed_count_dec = 0; ++ m_omx_output_busy = 0; ++ m_es_format = mmal_format_alloc(); } COpenMaxVideo::~COpenMaxVideo() -@@ -369,7 +374,10 @@ void COpenMaxVideo::Dispose() - m_finished = true; - pthread_mutex_unlock(&m_omx_output_mutex); - if (done) -+ { -+ assert(m_dts_queue.empty()); - m_myself.reset(); -+ } + { + #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); ++ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this); + #endif +- if (m_is_open) +- Close(); +- pthread_mutex_destroy(&m_omx_input_mutex); ++ assert(m_finished); ++ Reset(); ++ + pthread_mutex_destroy(&m_omx_output_mutex); +- sem_destroy(m_omx_decoder_state_change); +- free(m_omx_decoder_state_change); +-} + +-bool COpenMaxVideo::Open(CDVDStreamInfo &hints) +-{ +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); +- #endif ++ if (m_deint && m_deint->control && m_deint->control->is_enabled) ++ mmal_port_disable(m_deint->control); + +- OMX_ERRORTYPE omx_err = OMX_ErrorNone; +- std::string decoder_name; ++ if (m_dec && m_dec->control && m_dec->control->is_enabled) ++ mmal_port_disable(m_dec->control); + +- m_decoded_width = hints.width; +- m_decoded_height = hints.height; ++ if (m_dec_input && m_dec_input->is_enabled) ++ mmal_port_disable(m_dec_input); ++ m_dec_input = NULL; + +- switch (hints.codec) +- { +- case AV_CODEC_ID_H264: +- { +- switch(hints.profile) +- { +- case FF_PROFILE_H264_BASELINE: +- // (role name) video_decoder.avc +- // H.264 Baseline profile +- decoder_name = OMX_H264BASE_DECODER; +- break; +- case FF_PROFILE_H264_MAIN: +- // (role name) video_decoder.avc +- // H.264 Main profile +- decoder_name = OMX_H264MAIN_DECODER; +- break; +- case FF_PROFILE_H264_HIGH: +- // (role name) video_decoder.avc +- // H.264 Main profile +- decoder_name = OMX_H264HIGH_DECODER; +- break; +- default: +- return false; +- break; +- } +- } +- break; +- case AV_CODEC_ID_MPEG4: +- // (role name) video_decoder.mpeg4 +- // MPEG-4, DivX 4/5 and Xvid compatible +- decoder_name = OMX_MPEG4_DECODER; +- break; +- /* +- TODO: what mpeg4 formats are "ext" ???? +- case NvxStreamType_MPEG4Ext: +- // (role name) video_decoder.mpeg4 +- // MPEG-4, DivX 4/5 and Xvid compatible +- decoder_name = OMX_MPEG4EXT_DECODER; +- m_pFormatName = "omx-mpeg4"; +- break; +- */ +- case AV_CODEC_ID_MPEG2VIDEO: +- // (role name) video_decoder.mpeg2 +- // MPEG-2 +- decoder_name = OMX_MPEG2V_DECODER; +- break; +- case AV_CODEC_ID_VC1: +- // (role name) video_decoder.vc1 +- // VC-1, WMV9 +- decoder_name = OMX_VC1_DECODER; +- break; +- default: +- return false; +- break; +- } ++ if (m_dec_output && m_dec_output->is_enabled) ++ mmal_port_disable(m_dec_output); ++ m_dec_output = NULL; + +- // initialize OpenMAX. +- if (!Initialize(decoder_name)) +- { +- return false; +- } ++ if (m_deint_connection) ++ mmal_connection_destroy(m_deint_connection); ++ m_deint_connection = NULL; + +- // TODO: Find component from role name. +- // Get the port information. This will obtain information about the +- // number of ports and index of the first port. +- OMX_PORT_PARAM_TYPE port_param; +- OMX_INIT_STRUCTURE(port_param); +- omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamVideoInit, &port_param); +- if (omx_err) +- { +- Deinitialize(); +- return false; +- } +- m_omx_input_port = port_param.nStartPortNumber; +- m_omx_output_port = m_omx_input_port + 1; +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, +- "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x)\n", +- CLASSNAME, __func__, m_omx_decoder, m_omx_input_port, m_omx_output_port); +- #endif ++ if (m_deint && m_deint->is_enabled) ++ mmal_component_disable(m_deint); + +- // TODO: Set role for the component because components could have multiple roles. +- //QueryCodec(); ++ if (m_dec && m_dec->is_enabled) ++ mmal_component_disable(m_dec); + +- // Component will be in OMX_StateLoaded now so we can alloc omx input/output buffers. +- // we can only alloc them in OMX_StateLoaded state or if the component port is disabled +- // Alloc buffers for the omx input port. +- omx_err = AllocOMXInputBuffers(); +- if (omx_err) +- { +- Deinitialize(); +- return false; +- } +- // Alloc buffers for the omx output port. +- m_egl_display = g_Windowing.GetEGLDisplay(); +- m_egl_context = g_Windowing.GetEGLContext(); +- omx_err = AllocOMXOutputBuffers(); +- if (omx_err) +- { +- FreeOMXInputBuffers(false); +- Deinitialize(); +- return false; +- } ++ if (m_dec_input_pool) ++ mmal_pool_destroy(m_dec_input_pool); ++ m_dec_input_pool = NULL; + +- m_is_open = true; +- m_drop_state = false; +- m_videoplayback_done = false; ++ if (m_dec_output_pool) ++ mmal_pool_destroy(m_dec_output_pool); ++ m_dec_output_pool = NULL; + +- // crank it up. +- StartDecoder(); ++ if (m_deint) ++ mmal_component_destroy(m_deint); ++ m_deint = NULL; + +- return true; ++ if (m_dec) ++ mmal_component_destroy(m_dec); ++ m_dec = NULL; ++ mmal_format_free(m_es_format); ++ m_es_format = NULL; } - void COpenMaxVideo::SetDropState(bool bDrop) -@@ -730,6 +738,7 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes; - omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts); - omx_buffer->pAppPrivate = omx_buffer; -+ omx_buffer->pMarkData = (OMX_PTR)m_decode_frame_number; - memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen); +-void COpenMaxVideo::Close() ++void COpenMaxVideo::PortSettingsChanged(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + { +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); +- #endif +- if (m_omx_decoder) ++ MMAL_EVENT_FORMAT_CHANGED_T *fmt = mmal_event_format_changed_get(buffer); ++ mmal_format_copy(m_es_format, fmt->format); ++ m_changed_count++; ++ ++ if (m_es_format->es->video.crop.width && m_es_format->es->video.crop.height) + { +- if (m_omx_decoder_state != OMX_StateLoaded) +- StopDecoder(); +- Deinitialize(); ++ if (m_es_format->es->video.par.num && m_es_format->es->video.par.den) ++ m_aspect_ratio = (float)(m_es_format->es->video.par.num * m_es_format->es->video.crop.width) / (m_es_format->es->video.par.den * m_es_format->es->video.crop.height); ++ m_decoded_width = m_es_format->es->video.crop.width; ++ m_decoded_height = m_es_format->es->video.crop.height; ++ CLog::Log(LOGDEBUG, "%s::%s format changed: %dx%d %.2f frame:%d", CLASSNAME, __func__, m_decoded_width, m_decoded_height, m_aspect_ratio, m_changed_count); + } +- m_is_open = false; ++ else ++ CLog::Log(LOGERROR, "%s::%s format changed: Unexpected %dx%d", CLASSNAME, __func__, m_es_format->es->video.crop.width, m_es_format->es->video.crop.height); + } - demuxer_bytes -= omx_buffer->nFilledLen; -@@ -742,12 +751,18 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN; - if (pts == DVD_NOPTS_VALUE) // hijack an omx flag to indicate there wasn't a real timestamp - it will be returned with the picture (but otherwise ignored) - omx_buffer->nFlags |= OMX_BUFFERFLAG_PTS_INVALID; -- if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored) +-void COpenMaxVideo::SetDropState(bool bDrop) ++void COpenMaxVideo::dec_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + { +- m_drop_state = bDrop; ++ MMAL_STATUS_T status; + +- if (m_drop_state) ++ if (buffer->cmd == MMAL_EVENT_ERROR) ++ { ++ status = (MMAL_STATUS_T)*(uint32_t *)buffer->data; ++ CLog::Log(LOGERROR, "%s::%s Error (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ } ++ else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) + { +- OMX_ERRORTYPE omx_err; ++ CLog::Log(LOGDEBUG, "%s::%s format changed", CLASSNAME, __func__); ++ PortSettingsChanged(port, buffer); ++ } ++ else ++ CLog::Log(LOGERROR, "%s::%s other (cmd:%x data:%x)", CLASSNAME, __func__, buffer->cmd, *(uint32_t *)buffer->data); + +- // blow all but the last ready video frame +- pthread_mutex_lock(&m_omx_output_mutex); +- while (m_omx_output_ready.size() > 1) +- { +- m_dts_queue.pop(); +- OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_output_ready.front()->omx_buffer; +- m_omx_output_ready.pop(); +- // return the omx buffer back to OpenMax to fill. +- omx_err = OMX_FillThisBuffer(m_omx_decoder, omx_buffer); +- if (omx_err) +- CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- } +- pthread_mutex_unlock(&m_omx_output_mutex); ++ mmal_buffer_header_release(buffer); ++} + +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)\n", +- CLASSNAME, __func__, m_drop_state); +- #endif +- } ++static void dec_control_port_cb_static(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) ++{ ++ COpenMaxVideo *omx = reinterpret_cast(port->userdata); ++ omx->dec_control_port_cb(port, buffer); + } + +-int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) ++ ++static void dec_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + { +- if (pData) +- { +- int demuxer_bytes = iSize; +- uint8_t *demuxer_content = pData; ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p, len %d cmd:%x", CLASSNAME, __func__, port, buffer, buffer->length, buffer->cmd); ++#endif ++ mmal_buffer_header_release(buffer); ++} + +- // we need to queue then de-queue the demux packet, seems silly but +- // omx might not have a omx input buffer avaliable when we are called +- // and we must store the demuxer packet and try again later. +- omx_demux_packet demux_packet; +- demux_packet.dts = dts; +- demux_packet.pts = pts; + +- demux_packet.size = demuxer_bytes; +- demux_packet.buff = new OMX_U8[demuxer_bytes]; +- memcpy(demux_packet.buff, demuxer_content, demuxer_bytes); +- m_demux_queue.push(demux_packet); ++void COpenMaxVideo::dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ if (!(buffer->cmd == 0 && buffer->length > 0)) ++ CLog::Log(LOGDEBUG, "%s::%s port:%p buffer %p, len %d cmd:%x", CLASSNAME, __func__, port, buffer, buffer->length, buffer->cmd); ++#endif ++ bool kept = false; + +- // we can look at m_omx_input_avaliable.empty without needing to lock/unlock +- // try to send any/all demux packets to omx decoder. +- while (!m_omx_input_avaliable.empty() && !m_demux_queue.empty() ) ++ if (buffer->cmd == 0) ++ { ++ if (buffer->length > 0) + { +- OMX_ERRORTYPE omx_err; +- OMX_BUFFERHEADERTYPE* omx_buffer; +- +- demux_packet = m_demux_queue.front(); +- m_demux_queue.pop(); +- // need to lock here to retreve an input buffer and pop the queue +- pthread_mutex_lock(&m_omx_input_mutex); +- omx_buffer = m_omx_input_avaliable.front(); +- m_omx_input_avaliable.pop(); +- pthread_mutex_unlock(&m_omx_input_mutex); +- +- // delete the previous demuxer buffer +- delete [] omx_buffer->pBuffer; +- // setup a new omx_buffer. +- omx_buffer->nFlags = m_omx_input_eos ? OMX_BUFFERFLAG_EOS : 0; +- omx_buffer->nOffset = 0; +- omx_buffer->pBuffer = demux_packet.buff; +- omx_buffer->nAllocLen = demux_packet.size; +- omx_buffer->nFilledLen = demux_packet.size; +- omx_buffer->nTimeStamp = (demux_packet.pts == DVD_NOPTS_VALUE) ? 0 : demux_packet.pts * 1000.0; // in microseconds; +- omx_buffer->pAppPrivate = omx_buffer; +- omx_buffer->nInputPortIndex = m_omx_input_port; +- +- #if defined(OMX_DEBUG_EMPTYBUFFERDONE) +- CLog::Log(LOGDEBUG, +- "%s::%s - feeding decoder, omx_buffer->pBuffer(0x%p), demuxer_bytes(%d)\n", +- CLASSNAME, __func__, omx_buffer->pBuffer, demuxer_bytes); +- #endif +- // Give this omx_buffer to OpenMax to be decoded. +- omx_err = OMX_EmptyThisBuffer(m_omx_decoder, omx_buffer); +- if (omx_err) ++ assert(!(buffer->flags & MMAL_BUFFER_HEADER_FLAG_DECODEONLY)); ++ double dts = DVD_NOPTS_VALUE; ++ #ifdef DTS_QUEUE ++ pthread_mutex_lock(&m_omx_output_mutex); ++ if (!m_dts_queue.empty()) + { +- CLog::Log(LOGDEBUG, +- "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- return VC_ERROR; ++ dts = m_dts_queue.front(); ++ m_dts_queue.pop(); + } +- // only push if we are successful with feeding OMX_EmptyThisBuffer +- m_dts_queue.push(demux_packet.dts); ++ else assert(0); ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ #endif + +- // if m_omx_input_avaliable and/or demux_queue are now empty, +- // wait up to 20ms for OpenMax to consume a demux packet +- if (m_omx_input_avaliable.empty() || m_demux_queue.empty()) +- m_input_consumed_event.WaitMSec(1); + if (m_drop_state) + { -+ // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored) - omx_buffer->nFlags |= OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED; -+ m_droppedPics += m_deinterlace ? 2:1; ++ CLog::Log(LOGDEBUG, "%s::%s - dropping %p (drop:%d)", CLASSNAME, __func__, buffer, m_drop_state); + } -+ // always set this flag on input. It won't be set on second field of interlaced video. -+ omx_buffer->nFlags |= OMX_BUFFERFLAG_FIRST_FIELD; ++ else ++ { ++ COpenMaxVideoBuffer *omvb = new COpenMaxVideoBuffer(this); ++ m_omx_output_busy++; ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %p (%p) buffer_size(%u) dts:%.3f pts:%.3f flags:%x:%x frame:%d", ++ CLASSNAME, __func__, buffer, omvb, buffer->length, dts*1e-6, buffer->pts*1e-6, buffer->flags, buffer->type->video.flags, omvb->m_changed_count); ++#endif ++ omvb->mmal_buffer = buffer; ++ buffer->user_data = (void *)omvb; ++ omvb->m_changed_count = m_changed_count; ++ omvb->dts = dts; ++ omvb->width = m_decoded_width; ++ omvb->height = m_decoded_height; ++ omvb->m_aspect_ratio = m_aspect_ratio; ++ pthread_mutex_lock(&m_omx_output_mutex); ++ m_omx_output_ready.push(omvb); ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ kept = true; ++ } + } +- if (m_omx_input_avaliable.empty() && !m_demux_queue.empty()) +- m_input_consumed_event.WaitMSec(1); +- +- #if defined(OMX_DEBUG_VERBOSE) +- if (m_omx_input_avaliable.empty()) +- CLog::Log(LOGDEBUG, +- "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d)\n", +- CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes); +- #endif + } +- +- if (m_omx_output_ready.empty()) +- return VC_BUFFER; +- +- return VC_PICTURE | VC_BUFFER; +-} +- +-void COpenMaxVideo::Reset(void) +-{ +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); +- #endif +-/* +- // only reset OpenMax decoder if it's running +- if (m_omx_decoder_state == OMX_StateExecuting) ++ else if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) + { +- OMX_ERRORTYPE omx_err; +- +- omx_err = StopDecoder(); +- // Alloc OpenMax input buffers. +- omx_err = AllocOMXInputBuffers(); +- // Alloc OpenMax output buffers. +- omx_err = AllocOMXOutputBuffers(); +- +- omx_err = StartDecoder(); ++ PortSettingsChanged(port, buffer); + } +-*/ +- ::Sleep(100); ++ if (!kept) ++ mmal_buffer_header_release(buffer); + } - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x", -- CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags); -+ CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x frame:%d", -+ CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags, (int)omx_buffer->pMarkData); - #endif +-bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) ++static void dec_output_port_cb_static(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) + { +- while (m_omx_output_busy.size() > 1) +- { +- // fetch a output buffer and pop it off the busy list +- pthread_mutex_lock(&m_omx_output_mutex); +- OpenMaxVideoBuffer *buffer = m_omx_output_busy.front(); +- m_omx_output_busy.pop(); +- pthread_mutex_unlock(&m_omx_output_mutex); ++ COpenMaxVideo *omx = reinterpret_cast(port->userdata); ++ omx->dec_output_port_cb(port, buffer); ++} - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); -@@ -758,13 +773,16 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - } - if (demuxer_bytes == 0) - { -+ m_decode_frame_number++; - m_startframe = true; - #ifdef DTS_QUEUE - if (!m_drop_state) - { - // only push if we are successful with feeding OMX_EmptyThisBuffer -+ pthread_mutex_lock(&m_omx_output_mutex); - m_dts_queue.push(dts); - assert(m_dts_queue.size() < 32); -+ pthread_mutex_unlock(&m_omx_output_mutex); - } - #endif - if (buffer_to_free) -@@ -840,13 +858,18 @@ void COpenMaxVideo::Reset(void) - SetDropState(true); - SetDropState(false); - #ifdef DTS_QUEUE +- bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS; +- if (!done) +- { +- // return the omx buffer back to OpenMax to fill. +- OMX_ERRORTYPE omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer); +- if (omx_err) +- CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- } +- } ++bool COpenMaxVideo::change_dec_output_format() ++{ ++ MMAL_STATUS_T status; ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); + +- if (!m_omx_output_ready.empty()) ++#if 0 + { +- OpenMaxVideoBuffer *buffer; +- // fetch a output buffer and pop it off the ready list +- pthread_mutex_lock(&m_omx_output_mutex); +- buffer = m_omx_output_ready.front(); +- m_omx_output_ready.pop(); +- m_omx_output_busy.push(buffer); +- pthread_mutex_unlock(&m_omx_output_mutex); ++ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type = {{ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE, sizeof( interlace_type )}}; ++ status = mmal_port_parameter_get( m_dec_output, &interlace_type.hdr ); + +- pDvdVideoPicture->dts = DVD_NOPTS_VALUE; +- pDvdVideoPicture->pts = DVD_NOPTS_VALUE; +- pDvdVideoPicture->format = RENDER_FMT_OMXEGL; +- pDvdVideoPicture->openMax = this; +- pDvdVideoPicture->openMaxBuffer = buffer; +- +- if (!m_dts_queue.empty()) ++ if (status == MMAL_SUCCESS) ++ { ++ if (m_interlace_mode != interlace_type.eMode) + { +- pDvdVideoPicture->dts = m_dts_queue.front(); +- m_dts_queue.pop(); ++ CLog::Log(LOGDEBUG, "%s::%s Interlace mode %d->%d", CLASSNAME, __func__, m_interlace_mode, interlace_type.eMode); ++ m_interlace_mode = interlace_type.eMode; + } +- // nTimeStamp is in microseconds +- pDvdVideoPicture->pts = (buffer->omx_buffer->nTimeStamp == 0) ? DVD_NOPTS_VALUE : (double)buffer->omx_buffer->nTimeStamp / 1000.0; + } +- #if defined(OMX_DEBUG_VERBOSE) + else ++ CLog::Log(LOGERROR, "%s::%s Failed to query interlace type on %s (status=%x %s)", CLASSNAME, __func__, m_dec_output->name, status, mmal_status_to_string(status)); ++ } ++#endif ++ // todo: if we don't disable/enable we can do this from callback ++ mmal_format_copy(m_dec_output->format, m_es_format); ++ status = mmal_port_format_commit(m_dec_output); ++ if (status != MMAL_SUCCESS) + { +- CLog::Log(LOGDEBUG, "%s::%s - called but m_omx_output_ready is empty\n", +- CLASSNAME, __func__); ++ CLog::Log(LOGERROR, "%s::%s Failed to commit decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } +- #endif +- +- pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; +- pDvdVideoPicture->iFlags |= m_drop_state ? DVP_FLAG_DROPPED : 0; +- + return true; + } + +- +-// DecoderEmptyBufferDone -- OpenMax input buffer has been emptied +-OMX_ERRORTYPE COpenMaxVideo::DecoderEmptyBufferDone( +- OMX_HANDLETYPE hComponent, +- OMX_PTR pAppData, +- OMX_BUFFERHEADERTYPE* pBuffer) +-{ +- COpenMaxVideo *ctx = static_cast(pAppData); +-/* +- #if defined(OMX_DEBUG_EMPTYBUFFERDONE) +- CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n", +- CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0); +- #endif +-*/ +- // queue free input buffer to avaliable list. +- pthread_mutex_lock(&ctx->m_omx_input_mutex); +- ctx->m_omx_input_avaliable.push(pBuffer); +- ctx->m_input_consumed_event.Set(); +- pthread_mutex_unlock(&ctx->m_omx_input_mutex); +- +- return OMX_ErrorNone; +-} +- +-// DecoderFillBufferDone -- OpenMax output buffer has been filled +-OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone( +- OMX_HANDLETYPE hComponent, +- OMX_PTR pAppData, +- OMX_BUFFERHEADERTYPE* pBuffer) ++bool COpenMaxVideo::CreateDeinterlace() + { +- COpenMaxVideo *ctx = static_cast(pAppData); +- OpenMaxVideoBuffer *buffer = (OpenMaxVideoBuffer*)pBuffer->pAppPrivate; ++ MMAL_STATUS_T status; + +- #if defined(OMX_DEBUG_FILLBUFFERDONE) +- CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n", +- CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0); +- #endif ++ assert(!m_deint); ++ assert(m_dec_output == m_dec->output[0]); + +- if (!ctx->m_portChanging) ++ status = mmal_port_disable(m_dec_output); ++ if (status != MMAL_SUCCESS) + { +- // queue output omx buffer to ready list. +- pthread_mutex_lock(&ctx->m_omx_output_mutex); +- ctx->m_omx_output_ready.push(buffer); +- pthread_mutex_unlock(&ctx->m_omx_output_mutex); ++ CLog::Log(LOGERROR, "%s::%s Failed to disable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } + +- return OMX_ErrorNone; +-} ++ /* Create deinterlace filter */ ++ status = mmal_component_create("vc.ril.image_fx", &m_deint); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to create deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, sizeof(imfx_param)}, MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST, 1, {3}}; ++ status = mmal_port_parameter_set(m_deint->output[0], &imfx_param.hdr); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to set deinterlace parameters (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } + +-void COpenMaxVideo::QueryCodec(void) +-{ +- OMX_ERRORTYPE omx_err = OMX_ErrorNone; +- OMX_VIDEO_PARAM_PROFILELEVELTYPE port_param; +- OMX_INIT_STRUCTURE(port_param); ++ MMAL_PORT_T *m_deint_input = m_deint->input[0]; ++ m_deint_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; + +- port_param.nPortIndex = m_omx_input_port; ++ // Now connect the decoder output port to deinterlace input port ++ status = mmal_connection_create(&m_deint_connection, m_dec->output[0], m_deint->input[0], MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to connect deinterlacer component %s (status=%x %s)", CLASSNAME, __func__, m_deint->name, status, mmal_status_to_string(status)); ++ return false; ++ } + +- for (port_param.nProfileIndex = 0;; port_param.nProfileIndex++) ++ status = mmal_connection_enable(m_deint_connection); ++ if (status != MMAL_SUCCESS) + { +- omx_err = OMX_GetParameter(m_omx_decoder, +- OMX_IndexParamVideoProfileLevelQuerySupported, &port_param); +- if (omx_err) +- break; ++ CLog::Log(LOGERROR, "%s::%s Failed to enable connection %s (status=%x %s)", CLASSNAME, __func__, m_deint->name, status, mmal_status_to_string(status)); ++ return false; ++ } + +- omx_codec_capability omx_capability; +- omx_capability.level = port_param.eLevel; +- omx_capability.profile = port_param.eProfile; +- m_omx_decoder_capabilities.push_back(omx_capability); ++ mmal_format_copy(m_deint->output[0]->format, m_es_format); ++ status = mmal_port_format_commit(m_deint->output[0]); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to commit deint output format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } +-} + +-OMX_ERRORTYPE COpenMaxVideo::PrimeFillBuffers(void) +-{ +- OMX_ERRORTYPE omx_err = OMX_ErrorNone; +- OpenMaxVideoBuffer *buffer; ++ status = mmal_component_enable(m_deint); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable deinterlacer component %s (status=%x %s)", CLASSNAME, __func__, m_deint->name, status, mmal_status_to_string(status)); ++ return false; ++ } + +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); +- #endif +- // tell OpenMax to start filling output buffers +- for (size_t i = 0; i < m_omx_output_buffers.size(); i++) ++ m_deint->output[0]->buffer_size = m_deint->output[0]->buffer_size_min; ++ m_deint->output[0]->buffer_num = m_deint->output[0]->buffer_num_recommended; ++ m_deint->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ status = mmal_port_enable(m_deint->output[0], dec_output_port_cb_static); ++ if (status != MMAL_SUCCESS) + { +- buffer = m_omx_output_buffers[i]; +- // always set the port index. +- buffer->omx_buffer->nOutputPortIndex = m_omx_output_port; +- // Need to clear the EOS flag. +- buffer->omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS; +- buffer->omx_buffer->pAppPrivate = buffer; +- +- omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer); +- if (omx_err) +- CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); ++ CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } + +- return omx_err; ++ m_dec_output = m_deint->output[0]; ++ ++ return true; + } + +-OMX_ERRORTYPE COpenMaxVideo::AllocOMXInputBuffers(void) ++bool COpenMaxVideo::DestroyDeinterlace() + { +- OMX_ERRORTYPE omx_err = OMX_ErrorNone; ++ MMAL_STATUS_T status; + +- // Obtain the information about the decoder input port. +- OMX_PARAM_PORTDEFINITIONTYPE port_format; +- OMX_INIT_STRUCTURE(port_format); +- port_format.nPortIndex = m_omx_input_port; +- OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format); ++ assert(m_deint); ++ assert(m_dec_output == m_deint->output[0]); + +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, +- "%s::%s - iport(%d), nBufferCountMin(%lu), nBufferSize(%lu)\n", +- CLASSNAME, __func__, m_omx_input_port, port_format.nBufferCountMin, port_format.nBufferSize); +- #endif +- for (size_t i = 0; i < port_format.nBufferCountMin; i++) ++ status = mmal_port_disable(m_dec_output); ++ if (status != MMAL_SUCCESS) + { +- OMX_BUFFERHEADERTYPE *buffer = NULL; +- // use an external buffer that's sized according to actual demux +- // packet size, start at internal's buffer size, will get deleted when +- // we start pulling demuxer packets and using demux packet sized buffers. +- OMX_U8* data = new OMX_U8[port_format.nBufferSize]; +- omx_err = OMX_UseBuffer(m_omx_decoder, &buffer, m_omx_input_port, NULL, port_format.nBufferSize, data); +- if (omx_err) +- { +- CLog::Log(LOGERROR, "%s::%s - OMX_UseBuffer failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- return(omx_err); +- } +- m_omx_input_buffers.push_back(buffer); +- // don't have to lock/unlock here, we are not decoding +- m_omx_input_avaliable.push(buffer); ++ CLog::Log(LOGERROR, "%s::%s Failed to disable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } +- m_omx_input_eos = false; + +- return(omx_err); +-} +-OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(bool wait) +-{ +- OMX_ERRORTYPE omx_err = OMX_ErrorNone; +- +- /* +- omx_err = OMX_SendCommand(m_omx_decoder, OMX_CommandFlush, m_omx_input_port, 0); +- if (omx_err) +- CLog::Log(LOGERROR, "%s::%s - OMX_CommandFlush failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- else if (wait) +- sem_wait(m_omx_flush_input); +- */ +- +- // free omx input port buffers. +- for (size_t i = 0; i < m_omx_input_buffers.size(); i++) ++ status = mmal_connection_destroy(m_deint_connection); ++ if (status != MMAL_SUCCESS) + { +- // using external buffers (OMX_UseBuffer), free our external buffers +- // before calling OMX_FreeBuffer which frees the omx buffer. +- delete [] m_omx_input_buffers[i]->pBuffer; +- m_omx_input_buffers[i]->pBuffer = NULL; +- omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_input_port, m_omx_input_buffers[i]); ++ CLog::Log(LOGERROR, "%s::%s Failed to destroy deinterlace connection (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } +- m_omx_input_buffers.clear(); ++ m_deint_connection = NULL; + +- // empty input buffer queue. not decoding so don't need lock/unlock. +- while (!m_omx_input_avaliable.empty()) +- m_omx_input_avaliable.pop(); +- while (!m_demux_queue.empty()) +- m_demux_queue.pop(); +- while (!m_dts_queue.empty()) +- m_dts_queue.pop(); ++ status = mmal_component_disable(m_deint); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to disable deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } + +- return(omx_err); +-} ++ status = mmal_component_destroy(m_deint); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to destroy deinterlace component (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ m_deint = NULL; + +-void COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata) +-{ +- COpenMaxVideo *omx = static_cast(userdata); +- omx->AllocOMXOutputEGLTextures(); +-} ++ m_dec->output[0]->buffer_size = m_dec->output[0]->buffer_size_min; ++ m_dec->output[0]->buffer_num = m_dec->output[0]->buffer_num_recommended; ++ m_dec->output[0]->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ status = mmal_port_enable(m_dec->output[0], dec_output_port_cb_static); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } + +-void COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata) +-{ +- COpenMaxVideo *omx = static_cast(userdata); +- omx->FreeOMXOutputEGLTextures(true); ++ m_dec_output = m_dec->output[0]; ++ return true; + } + +-OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputBuffers(void) ++bool COpenMaxVideo::SendCodecConfigData() + { +- OMX_ERRORTYPE omx_err; +- +- if ( g_application.IsCurrentThread() ) ++ MMAL_STATUS_T status; ++ // send code config data ++ MMAL_BUFFER_HEADER_T *buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500); ++ if (!buffer) + { +- omx_err = AllocOMXOutputEGLTextures(); ++ CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__); ++ return false; + } +- else ++ ++ mmal_buffer_header_reset(buffer); ++ buffer->cmd = 0; ++ buffer->length = std::min(m_hints.extrasize, buffer->alloc_size); ++ memcpy(buffer->data, m_hints.extradata, buffer->length); ++ buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_CONFIG; ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d flags:%x", CLASSNAME, __func__, buffer, buffer->length, buffer->flags); ++#endif ++ status = mmal_port_send_buffer(m_dec_input, buffer); ++ if (status != MMAL_SUCCESS) + { +- ThreadMessageCallback callbackData; +- callbackData.callback = &CallbackAllocOMXEGLTextures; +- callbackData.userptr = (void *)this; ++ CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } ++ return true; ++} + +- ThreadMessage tMsg; +- tMsg.dwMessage = TMSG_CALLBACK; +- tMsg.lpVoid = (void*)&callbackData; ++bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself) ++{ ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s useomx:%d software:%d %dx%d", CLASSNAME, __func__, CSettings::Get().GetBool("videoplayer.useomx"), hints.software, hints.width, hints.height); ++ #endif + +- g_application.getApplicationMessenger().SendMessage(tMsg, true); ++ // we always qualify even if DVDFactoryCodec does this too. ++ if (!CSettings::Get().GetBool("videoplayer.useomx") || hints.software) ++ return false; + +- omx_err = OMX_ErrorNone; +- } ++ m_hints = hints; ++ MMAL_STATUS_T status; ++ MMAL_PARAMETER_BOOLEAN_T error_concealment; + +- return omx_err; +-} ++ m_myself = myself; ++ m_decoded_width = hints.width; ++ m_decoded_height = hints.height; ++ m_forced_aspect_ratio = hints.forced_aspect; ++ m_aspect_ratio = hints.aspect; + +-OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputBuffers(bool wait) +-{ +- OMX_ERRORTYPE omx_err = FreeOMXOutputEGLTextures(wait); ++ switch (hints.codec) ++ { ++ case AV_CODEC_ID_H264: ++ // H.264 ++ m_codingType = MMAL_ENCODING_H264; ++ m_pFormatName = "mmal-h264"; ++ break; ++ case AV_CODEC_ID_H263: ++ case AV_CODEC_ID_MPEG4: ++ // MPEG-4, DivX 4/5 and Xvid compatible ++ m_codingType = MMAL_ENCODING_MP4V; ++ m_pFormatName = "mmal-mpeg4"; ++ break; ++ case AV_CODEC_ID_MPEG1VIDEO: ++ case AV_CODEC_ID_MPEG2VIDEO: ++ // MPEG-2 ++ m_codingType = MMAL_ENCODING_MP2V; ++ m_pFormatName = "mmal-mpeg2"; ++ break; ++ case AV_CODEC_ID_VP6: ++ // this form is encoded upside down ++ // fall through ++ case AV_CODEC_ID_VP6F: ++ case AV_CODEC_ID_VP6A: ++ // VP6 ++ m_codingType = MMAL_ENCODING_VP6; ++ m_pFormatName = "mmal-vp6"; ++ break; ++ case AV_CODEC_ID_VP8: ++ // VP8 ++ m_codingType = MMAL_ENCODING_VP8; ++ m_pFormatName = "mmal-vp8"; ++ break; ++ case AV_CODEC_ID_THEORA: ++ // theora ++ m_codingType = MMAL_ENCODING_THEORA; ++ m_pFormatName = "mmal-theora"; ++ break; ++ case AV_CODEC_ID_MJPEG: ++ case AV_CODEC_ID_MJPEGB: ++ // mjpg ++ m_codingType = MMAL_ENCODING_MJPEG; ++ m_pFormatName = "mmal-mjpg"; ++ break; ++ case AV_CODEC_ID_VC1: ++ case AV_CODEC_ID_WMV3: ++ // VC-1, WMV9 ++ m_codingType = MMAL_ENCODING_WVC1; ++ m_pFormatName = "mmal-vc1"; ++ break; ++ default: ++ CLog::Log(LOGERROR, "%s::%s : Video codec unknown: %x", CLASSNAME, __func__, hints.codec); ++ return false; ++ break; ++ } + +- return omx_err; +-} ++ if ( (m_codingType == MMAL_ENCODING_MP2V && !g_RBP.GetCodecMpg2() ) || ++ (m_codingType == MMAL_ENCODING_WVC1 && !g_RBP.GetCodecWvc1() ) ) ++ { ++ CLog::Log(LOGWARNING, "%s::%s Codec %s is not supported", CLASSNAME, __func__, m_pFormatName); ++ return false; ++ } + +-OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void) +-{ +- OMX_ERRORTYPE omx_err; ++ // initialize mmal. ++ status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &m_dec); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to create MMAL decoder component %s (status=%x %s)", CLASSNAME, __func__, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status)); ++ return false; ++ } + +- if (!eglCreateImageKHR) ++ m_dec->control->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ status = mmal_port_enable(m_dec->control, dec_control_port_cb_static); ++ if (status != MMAL_SUCCESS) + { +- GETEXTENSION(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR); ++ CLog::Log(LOGERROR, "%s::%s Failed to enable decoder control port %s (status=%x %s)", CLASSNAME, __func__, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, status, mmal_status_to_string(status)); ++ return false; + } + +- EGLint attrib = EGL_NONE; +- OpenMaxVideoBuffer *egl_buffer; ++ m_dec_input = m_dec->input[0]; + +- // Obtain the information about the output port. +- OMX_PARAM_PORTDEFINITIONTYPE port_format; +- OMX_INIT_STRUCTURE(port_format); +- port_format.nPortIndex = m_omx_output_port; +- omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format); ++ m_dec_input->format->type = MMAL_ES_TYPE_VIDEO; ++ m_dec_input->format->encoding = m_codingType; ++ if (m_hints.width && m_hints.height) ++ { ++ m_dec_input->format->es->video.crop.width = m_hints.width; ++ m_dec_input->format->es->video.crop.height = m_hints.height; + +- #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, +- "%s::%s (1) - oport(%d), nFrameWidth(%lu), nFrameHeight(%lu), nStride(%lx), nBufferCountMin(%lu), nBufferSize(%lu)\n", +- CLASSNAME, __func__, m_omx_output_port, +- port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride, +- port_format.nBufferCountMin, port_format.nBufferSize); +- #endif ++ m_dec_input->format->es->video.width = ALIGN_UP(m_hints.width, 32); ++ m_dec_input->format->es->video.height = ALIGN_UP(m_hints.height, 16); ++ } ++ m_dec_input->format->flags |= MMAL_ES_FORMAT_FLAG_FRAMED; ++ ++ error_concealment.hdr.id = MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT; ++ error_concealment.hdr.size = sizeof(MMAL_PARAMETER_BOOLEAN_T); ++ error_concealment.enable = MMAL_FALSE; ++ status = mmal_port_parameter_set(m_dec_input, &error_concealment.hdr); ++ if (status != MMAL_SUCCESS) ++ CLog::Log(LOGERROR, "%s::%s Failed to disable error concealment on %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); + +- glActiveTexture(GL_TEXTURE0); ++ status = mmal_port_parameter_set_uint32(m_dec_input, MMAL_PARAMETER_EXTRA_BUFFERS, 5); ++ if (status != MMAL_SUCCESS) ++ CLog::Log(LOGERROR, "%s::%s Failed to enable extra buffers on %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); + +- for (size_t i = 0; i < port_format.nBufferCountMin; i++) ++ status = mmal_port_format_commit(m_dec_input); ++ if (status != MMAL_SUCCESS) + { +- egl_buffer = new OpenMaxVideoBuffer; +- memset(egl_buffer, 0, sizeof(*egl_buffer)); +- egl_buffer->width = m_decoded_width; +- egl_buffer->height = m_decoded_height; +- +- glGenTextures(1, &egl_buffer->texture_id); +- glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id); +- +- // create space for buffer with a texture +- glTexImage2D( +- GL_TEXTURE_2D, // target +- 0, // level +- GL_RGBA, // internal format +- m_decoded_width, // width +- m_decoded_height, // height +- 0, // border +- GL_RGBA, // format +- GL_UNSIGNED_BYTE, // type +- NULL); // pixels -- will be provided later +- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +- +- // create EGLImage from texture +- egl_buffer->egl_image = eglCreateImageKHR( +- m_egl_display, +- m_egl_context, +- EGL_GL_TEXTURE_2D_KHR, +- (EGLClientBuffer)(egl_buffer->texture_id), +- &attrib); +- if (!egl_buffer->egl_image) +- { +- CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage\n", CLASSNAME, __func__); +- return(OMX_ErrorUndefined); +- } +- egl_buffer->index = i; ++ CLog::Log(LOGERROR, "%s::%s Failed to commit format for decoder input port %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); ++ return false; ++ } ++ m_dec_input->buffer_size = m_dec_input->buffer_size_recommended; ++ m_dec_input->buffer_num = m_dec_input->buffer_num_recommended; + +- // tell decoder output port that it will be using EGLImage +- omx_err = OMX_UseEGLImage( +- m_omx_decoder, &egl_buffer->omx_buffer, m_omx_output_port, egl_buffer, egl_buffer->egl_image); +- if (omx_err) +- { +- CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- return(omx_err); +- } +- m_omx_output_buffers.push_back(egl_buffer); ++ m_dec_input->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ status = mmal_port_enable(m_dec_input, dec_input_port_cb); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable decoder input port %s (status=%x %s)", CLASSNAME, __func__, m_dec_input->name, status, mmal_status_to_string(status)); ++ return false; ++ } ++ ++ m_dec_output = m_dec->output[0]; ++ ++ // set up initial decoded frame format - will likely change from this ++ m_dec_output->format->encoding = MMAL_ENCODING_OPAQUE; ++ mmal_format_copy(m_es_format, m_dec_output->format); + +- CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d\n", +- CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height); ++ status = mmal_port_format_commit(m_dec_output); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to commit decoder output format (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } +- m_omx_output_eos = false; +- while (!m_omx_output_busy.empty()) +- m_omx_output_busy.pop(); +- while (!m_omx_output_ready.empty()) +- m_omx_output_ready.pop(); + +- return omx_err; +-} ++ m_dec_output->buffer_size = m_dec_output->buffer_size_min; ++ m_dec_output->buffer_num = m_dec_output->buffer_num_recommended; ++ m_dec_output->userdata = (struct MMAL_PORT_USERDATA_T *)this; ++ status = mmal_port_enable(m_dec_output, dec_output_port_cb_static); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable decoder output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; ++ } + +-OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait) +-{ +- OMX_ERRORTYPE omx_err = OMX_ErrorNone; +- OpenMaxVideoBuffer *egl_buffer; ++ status = mmal_component_enable(m_dec); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed to enable decoder component %s (status=%x %s)", CLASSNAME, __func__, m_dec->name, status, mmal_status_to_string(status)); ++ return false; ++ } + +- if (!eglDestroyImageKHR) ++ m_dec_input_pool = mmal_pool_create(m_dec_input->buffer_num, m_dec_input->buffer_size); ++ if (!m_dec_input_pool) + { +- GETEXTENSION(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR); ++ CLog::Log(LOGERROR, "%s::%s Failed to create pool for decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } + +- for (size_t i = 0; i < m_omx_output_buffers.size(); i++) ++ m_dec_output_pool = mmal_pool_create(m_dec_output->buffer_num, m_dec_output->buffer_size); ++ if(!m_dec_output_pool) + { +- egl_buffer = m_omx_output_buffers[i]; +- // tell decoder output port to stop using the EGLImage +- omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_output_port, egl_buffer->omx_buffer); +- // destroy egl_image +- eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image); +- // free texture +- glDeleteTextures(1, &egl_buffer->texture_id); +- delete egl_buffer; ++ CLog::Log(LOGERROR, "%s::%s Failed to create pool for decode output port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return false; + } +- m_omx_output_buffers.clear(); + +- return omx_err; +-} ++ if (!SendCodecConfigData()) ++ return false; + ++ m_drop_state = false; ++ m_startframe = false; + +-//////////////////////////////////////////////////////////////////////////////////////////// +-// DecoderEventHandler -- OMX event callback +-OMX_ERRORTYPE COpenMaxVideo::DecoderEventHandler( +- OMX_HANDLETYPE hComponent, +- OMX_PTR pAppData, +- OMX_EVENTTYPE eEvent, +- OMX_U32 nData1, +- OMX_U32 nData2, +- OMX_PTR pEventData) +-{ +- OMX_ERRORTYPE omx_err; +- COpenMaxVideo *ctx = static_cast(pAppData); ++ return true; ++} + +-/* ++void COpenMaxVideo::Dispose() ++{ ++ // we are happy to exit, but let last shared pointer being deleted trigger the destructor ++ bool done = false; ++ Reset(); + pthread_mutex_lock(&m_omx_output_mutex); - while (!m_dts_queue.empty()) - m_dts_queue.pop(); ++ if (!m_omx_output_busy) ++ done = true; ++ m_finished = true; + pthread_mutex_unlock(&m_omx_output_mutex); - #endif + #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, +- "COpenMax::%s - hComponent(0x%p), eEvent(0x%x), nData1(0x%lx), nData2(0x%lx), pEventData(0x%p)\n", +- __func__, hComponent, eEvent, nData1, nData2, pEventData); ++ CLog::Log(LOGDEBUG, "%s::%s dts_queue(%d) ready_queue(%d) busy_queue(%d) done:%d", CLASSNAME, __func__, m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy, done); + #endif +-*/ ++ if (done) ++ { ++ assert(m_dts_queue.empty()); ++ m_myself.reset(); ++ } ++} - while (!m_demux_queue.empty()) - m_demux_queue.pop(); - m_startframe = false; +- switch (eEvent) ++void COpenMaxVideo::SetDropState(bool bDrop) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ if (m_drop_state != bDrop) ++ CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)", CLASSNAME, __func__, bDrop); ++#endif ++ m_drop_state = bDrop; ++ if (m_drop_state) + { +- case OMX_EventCmdComplete: +- switch(nData1) +- { +- case OMX_CommandStateSet: +- ctx->m_omx_decoder_state = (int)nData2; +- switch (ctx->m_omx_decoder_state) +- { +- case OMX_StateInvalid: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateInvalid\n", CLASSNAME, __func__); +- break; +- case OMX_StateLoaded: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateLoaded\n", CLASSNAME, __func__); +- break; +- case OMX_StateIdle: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateIdle\n", CLASSNAME, __func__); +- break; +- case OMX_StateExecuting: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateExecuting\n", CLASSNAME, __func__); +- break; +- case OMX_StatePause: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_StatePause\n", CLASSNAME, __func__); +- break; +- case OMX_StateWaitForResources: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_StateWaitForResources\n", CLASSNAME, __func__); +- break; +- default: +- CLog::Log(LOGDEBUG, +- "%s::%s - Unknown OMX_Statexxxxx, state(%d)\n", +- CLASSNAME, __func__, ctx->m_omx_decoder_state); +- break; +- } +- sem_post(ctx->m_omx_decoder_state_change); +- break; +- case OMX_CommandFlush: +- /* +- if (OMX_ALL == (int)nData2) +- { +- sem_post(ctx->m_omx_flush_input); +- sem_post(ctx->m_omx_flush_output); +- CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input/output\n",__func__); +- } +- else if (ctx->m_omx_input_port == (int)nData2) +- { +- sem_post(ctx->m_omx_flush_input); +- CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input\n",__func__); +- } +- else if (ctx->m_omx_output_port == (int)nData2) +- { +- sem_post(ctx->m_omx_flush_output); +- CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush ouput\n",__func__); +- } +- else +- */ +- { +- #if defined(OMX_DEBUG_EVENTHANDLER) +- CLog::Log(LOGDEBUG, +- "%s::%s - OMX_CommandFlush, nData2(0x%lx)\n", +- CLASSNAME, __func__, nData2); +- #endif +- } +- break; +- case OMX_CommandPortDisable: +- #if defined(OMX_DEBUG_EVENTHANDLER) +- CLog::Log(LOGDEBUG, +- "%s::%s - OMX_CommandPortDisable, nData1(0x%lx), nData2(0x%lx)\n", +- CLASSNAME, __func__, nData1, nData2); +- #endif +- if (ctx->m_omx_output_port == (int)nData2) +- { +- // Got OMX_CommandPortDisable event, alloc new buffers for the output port. +- ctx->AllocOMXOutputBuffers(); +- omx_err = OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortEnable, ctx->m_omx_output_port, NULL); +- } +- break; +- case OMX_CommandPortEnable: +- #if defined(OMX_DEBUG_EVENTHANDLER) +- CLog::Log(LOGDEBUG, +- "%s::%s - OMX_CommandPortEnable, nData1(0x%lx), nData2(0x%lx)\n", +- CLASSNAME, __func__, nData1, nData2); +- #endif +- if (ctx->m_omx_output_port == (int)nData2) +- { +- // Got OMX_CommandPortEnable event. +- // OMX_CommandPortDisable will have re-alloced new ones so re-prime +- ctx->PrimeFillBuffers(); +- } +- ctx->m_portChanging = false; +- break; +- #if defined(OMX_DEBUG_EVENTHANDLER) +- case OMX_CommandMarkBuffer: +- CLog::Log(LOGDEBUG, +- "%s::%s - OMX_CommandMarkBuffer, nData1(0x%lx), nData2(0x%lx)\n", +- CLASSNAME, __func__, nData1, nData2); +- break; +- #endif +- } +- break; +- case OMX_EventBufferFlag: +- if (ctx->m_omx_decoder == hComponent && (nData2 & OMX_BUFFERFLAG_EOS)) { +- #if defined(OMX_DEBUG_EVENTHANDLER) +- if(ctx->m_omx_input_port == (int)nData1) +- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(input)\n", +- CLASSNAME, __func__); +- #endif +- if(ctx->m_omx_output_port == (int)nData1) +- { +- ctx->m_videoplayback_done = true; +- #if defined(OMX_DEBUG_EVENTHANDLER) +- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(output)\n", +- CLASSNAME, __func__); +- #endif +- } +- } +- break; +- case OMX_EventPortSettingsChanged: +- #if defined(OMX_DEBUG_EVENTHANDLER) +- CLog::Log(LOGDEBUG, +- "%s::%s - OMX_EventPortSettingsChanged(output)\n", CLASSNAME, __func__); +- #endif +- // not sure nData2 is the input/output ports in this call, docs don't say +- if (ctx->m_omx_output_port == (int)nData2) ++ while (1) ++ { ++ COpenMaxVideoBuffer *buffer = NULL; ++ pthread_mutex_lock(&m_omx_output_mutex); ++ // fetch a output buffer and pop it off the ready list ++ if (!m_omx_output_ready.empty()) + { +- // free the current OpenMax output buffers, you must do this before sending +- // OMX_CommandPortDisable to component as it expects output buffers +- // to be freed before it will issue a OMX_CommandPortDisable event. +- ctx->m_portChanging = true; +- OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortDisable, ctx->m_omx_output_port, NULL); +- omx_err = ctx->FreeOMXOutputBuffers(false); ++ buffer = m_omx_output_ready.front(); ++ m_omx_output_ready.pop(); + } +- break; +- #if defined(OMX_DEBUG_EVENTHANDLER) +- case OMX_EventMark: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventMark\n", CLASSNAME, __func__); +- break; +- case OMX_EventResourcesAcquired: +- CLog::Log(LOGDEBUG, "%s::%s - OMX_EventResourcesAcquired\n", CLASSNAME, __func__); +- break; +- #endif +- case OMX_EventError: +- switch((OMX_S32)nData1) +- { +- case OMX_ErrorInsufficientResources: +- CLog::Log(LOGERROR, "%s::%s - OMX_EventError, insufficient resources\n", +- CLASSNAME, __func__); +- // we are so frack'ed +- //exit(0); +- break; +- case OMX_ErrorFormatNotDetected: +- CLog::Log(LOGERROR, "%s::%s - OMX_EventError, cannot parse input stream\n", +- CLASSNAME, __func__); +- break; +- case OMX_ErrorPortUnpopulated: +- // silently ignore these. We can get them when setting OMX_CommandPortDisable +- // on the output port and the component flushes the output buffers. +- break; +- case OMX_ErrorStreamCorrupt: +- CLog::Log(LOGERROR, "%s::%s - OMX_EventError, Bitstream corrupt\n", +- CLASSNAME, __func__); +- ctx->m_videoplayback_done = true; ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ if (buffer) ++ ReleaseOpenMaxBuffer(buffer); ++ else + break; +- default: +- CLog::Log(LOGERROR, "%s::%s - OMX_EventError detected, nData1(0x%lx), nData2(0x%lx)\n", +- CLASSNAME, __func__, nData1, nData2); +- break; +- } +- // do this so we don't hang on errors +- /* +- sem_post(ctx->m_omx_flush_input); +- sem_post(ctx->m_omx_flush_output); +- */ +- sem_post(ctx->m_omx_decoder_state_change); +- break; +- default: +- CLog::Log(LOGWARNING, +- "%s::%s - Unknown eEvent(0x%x), nData1(0x%lx), nData2(0x%lx)\n", +- CLASSNAME, __func__, eEvent, nData1, nData2); +- break; ++ } + } +- +- return OMX_ErrorNone; + } + +-// StartPlayback -- Kick off video playback. +-OMX_ERRORTYPE COpenMaxVideo::StartDecoder(void) ++int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) + { +- OMX_ERRORTYPE omx_err; +- + #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); ++ //CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f dts_queue(%d) ready_queue(%d) busy_queue(%d)", ++ // CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy); + #endif + +- // transition decoder component to IDLE state +- omx_err = SetStateForComponent(OMX_StateIdle); +- if (omx_err) ++ unsigned int demuxer_bytes = 0; ++ uint8_t *demuxer_content = NULL; ++ MMAL_BUFFER_HEADER_T *buffer; ++ MMAL_STATUS_T status; ++ ++ while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) ++ Recycle(buffer); ++ // we need to queue then de-queue the demux packet, seems silly but ++ // omx might not have a omx input buffer available when we are called ++ // and we must store the demuxer packet and try again later. ++ // try to send any/all demux packets to omx decoder. ++ unsigned space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size; ++ if (pData && m_demux_queue.empty() && space >= (unsigned int)iSize) + { +- CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- return omx_err; ++ demuxer_bytes = iSize; ++ demuxer_content = pData; ++ } ++ else if (pData && iSize) ++ { ++ omx_demux_packet demux_packet; ++ demux_packet.dts = dts; ++ demux_packet.pts = pts; ++ demux_packet.size = iSize; ++ demux_packet.buff = new uint8_t[iSize]; ++ memcpy(demux_packet.buff, pData, iSize); ++ m_demux_queue.push(demux_packet); + } + +- // transition decoder component to executing state +- omx_err = SetStateForComponent(OMX_StateExecuting); +- if (omx_err) ++ uint8_t *buffer_to_free = NULL; ++ ++ while (1) ++ { ++ while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) ++ Recycle(buffer); ++ ++ space = mmal_queue_length(m_dec_input_pool->queue) * m_dec_input->buffer_size; ++ if (!demuxer_bytes && !m_demux_queue.empty()) ++ { ++ omx_demux_packet &demux_packet = m_demux_queue.front(); ++ if (space >= (unsigned int)demux_packet.size) ++ { ++ // need to lock here to retrieve an input buffer and pop the queue ++ m_demux_queue.pop(); ++ demuxer_bytes = (unsigned int)demux_packet.size; ++ demuxer_content = demux_packet.buff; ++ buffer_to_free = demux_packet.buff; ++ dts = demux_packet.dts; ++ pts = demux_packet.pts; ++ } ++ } ++ if (demuxer_content) ++ { ++ // 500ms timeout ++ buffer = mmal_queue_timedwait(m_dec_input_pool->queue, 500); ++ if (!buffer) ++ { ++ CLog::Log(LOGERROR, "%s::%s - mmal_queue_get failed", CLASSNAME, __func__); ++ return VC_ERROR; ++ } ++ ++ mmal_buffer_header_reset(buffer); ++ buffer->cmd = 0; ++ if (m_startframe && pts == DVD_NOPTS_VALUE) ++ pts = 0; ++ buffer->pts = pts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : pts; ++ buffer->dts = dts == DVD_NOPTS_VALUE ? MMAL_TIME_UNKNOWN : dts; ++ buffer->length = demuxer_bytes > buffer->alloc_size ? buffer->alloc_size : demuxer_bytes; ++ buffer->user_data = (void *)m_decode_frame_number; ++ ++ // Request decode only (maintain ref frames, but don't return a picture) ++ if (m_drop_state) ++ buffer->flags |= MMAL_BUFFER_HEADER_FLAG_DECODEONLY; ++ ++ memcpy(buffer->data, demuxer_content, buffer->length); ++ demuxer_bytes -= buffer->length; ++ demuxer_content += buffer->length; ++ ++ if (demuxer_bytes == 0) ++ buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END; ++ ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d/%-6d dts:%.3f pts:%.3f flags:%x dts_queue(%d) ready_queue(%d) busy_queue(%d)", ++ CLASSNAME, __func__, buffer, iSize-demuxer_bytes, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, buffer->flags, m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy); ++ #endif ++ status = mmal_port_send_buffer(m_dec_input, buffer); ++ if (status != MMAL_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s::%s Failed send buffer to decoder input port (status=%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return VC_ERROR; ++ } ++ ++ if (demuxer_bytes == 0) ++ { ++ m_decode_frame_number++; ++ m_startframe = true; ++ #ifdef DTS_QUEUE ++ if (m_drop_state) ++ { ++ m_droppedPics += m_deint ? 2:1; ++ } ++ else ++ { ++ // only push if we are successful with feeding OMX_EmptyThisBuffer ++ pthread_mutex_lock(&m_omx_output_mutex); ++ m_dts_queue.push(dts); ++ if (m_deint) ++ m_dts_queue.push(DVD_NOPTS_VALUE); ++ //assert(m_dts_queue.size() < 5000); ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ } ++ #endif ++ if (m_changed_count_dec != m_changed_count) ++ { ++ CLog::Log(LOGDEBUG, "%s::%s format changed frame:%d(%d)", CLASSNAME, __func__, m_changed_count_dec, m_changed_count); ++ m_changed_count_dec = m_changed_count; ++ if (!change_dec_output_format()) ++ { ++ CLog::Log(LOGERROR, "%s::%s - change_dec_output_format() failed", CLASSNAME, __func__); ++ return VC_ERROR; ++ } ++ } ++ EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++#if 0 ++ { ++ bool deinterlace = m_interlace_mode != MMAL_InterlaceProgressive; ++ ++ if (deinterlace_request == VS_DEINTERLACEMODE_OFF) ++ deinterlace = false; ++ else if (deinterlace_request == VS_DEINTERLACEMODE_FORCE) ++ deinterlace = true; ++ ++ if (!deinterlace && m_deint) ++ DestroyDeinterlace(); ++ else if (deinterlace && !m_deint) ++ CreateDeinterlace(); ++ } ++#endif ++ if (buffer_to_free) ++ { ++ delete [] buffer_to_free; ++ buffer_to_free = NULL; ++ demuxer_content = NULL; ++ continue; ++ } ++ while (buffer = mmal_queue_get(m_dec_output_pool->queue), buffer) ++ Recycle(buffer); ++ } ++ } ++ if (!demuxer_bytes) ++ break; ++ } ++ int ret = 0; ++ if (!m_omx_output_ready.empty()) ++ { ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - got output picture:%d", CLASSNAME, __func__, m_omx_output_ready.size()); ++ #endif ++ ret |= VC_PICTURE; ++ } ++ if (mmal_queue_length(m_dec_input_pool->queue) > 0) + { +- CLog::Log(LOGERROR, "%s::%s - setting OMX_StateExecuting failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- return omx_err; ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - got space for output:%d", CLASSNAME, __func__, mmal_queue_length(m_dec_input_pool->queue)); ++ #endif ++ ret |= VC_BUFFER; + } ++ return ret; ++} ++ ++void COpenMaxVideo::Reset(void) ++{ ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); ++ #endif ++ ++ if (m_dec_input) ++ mmal_port_disable(m_dec_input); ++ if (m_deint_connection) ++ mmal_connection_disable(m_deint_connection); ++ if (m_dec_output) ++ mmal_port_disable(m_dec_output); ++ if (m_dec_input) ++ mmal_port_enable(m_dec_input, dec_input_port_cb); ++ if (m_deint_connection) ++ mmal_connection_enable(m_deint_connection); ++ if (m_dec_output) ++ mmal_port_enable(m_dec_output, dec_output_port_cb_static); ++ ++ // blow all ready video frames ++ bool old_drop_state = m_drop_state; ++ SetDropState(true); ++#ifdef DTS_QUEUE ++ pthread_mutex_lock(&m_omx_output_mutex); ++ while(!m_dts_queue.empty()) ++ m_dts_queue.pop(); ++ while (!m_demux_queue.empty()) ++ m_demux_queue.pop(); ++ pthread_mutex_unlock(&m_omx_output_mutex); ++#endif ++ if (!old_drop_state) ++ SetDropState(false); ++ ++ SendCodecConfigData(); ++ ++ m_startframe = false; + m_decoderPts = DVD_NOPTS_VALUE; + m_droppedPics = 0; + m_decode_frame_number = 1; ++} + +- //prime the omx output buffers. +- PrimeFillBuffers(); + +- return omx_err; ++void COpenMaxVideo::ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p (%d)", CLASSNAME, __func__, buffer, m_omx_output_busy); ++#endif ++ ++ mmal_buffer_header_release(buffer->mmal_buffer); } +-// StopPlayback -- Stop video playback +-OMX_ERRORTYPE COpenMaxVideo::StopDecoder(void) ++void COpenMaxVideo::Recycle(MMAL_BUFFER_HEADER_T *buffer) + { +- OMX_ERRORTYPE omx_err; ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, buffer); ++#endif -@@ -928,26 +951,17 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) - } - } ++ MMAL_STATUS_T status; ++ mmal_buffer_header_reset(buffer); ++ buffer->cmd = 0; + #if defined(OMX_DEBUG_VERBOSE) +- CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__); ++ CLog::Log(LOGDEBUG, "%s::%s Send buffer %p from pool to decoder output port %p dts_queue(%d) ready_queue(%d) busy_queue(%d)", CLASSNAME, __func__, buffer, m_dec_output, ++ m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy); + #endif +- // transition decoder component from executing to idle +- omx_err = SetStateForComponent(OMX_StateIdle); +- if (omx_err) ++ status = mmal_port_send_buffer(m_dec_output, buffer); ++ if (status != MMAL_SUCCESS) + { +- CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); +- return omx_err; ++ CLog::Log(LOGERROR, "%s::%s - Failed send buffer to decoder output port (status=0%x %s)", CLASSNAME, __func__, status, mmal_status_to_string(status)); ++ return; + } ++} --#ifdef DTS_QUEUE -- if (!m_deinterlace_second_field) -- { -- assert(!m_dts_queue.empty()); -- pDvdVideoPicture->dts = m_dts_queue.front(); -- m_dts_queue.pop(); -- } -- if (m_deinterlace) -- m_deinterlace_second_field = !m_deinterlace_second_field; --#endif - // nTimeStamp is in microseconds +- // we can free our allocated port buffers in OMX_StateIdle state. +- // free OpenMax input buffers. +- FreeOMXInputBuffers(true); +- // free OpenMax output buffers. +- FreeOMXOutputBuffers(true); ++void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer) ++{ ++ // remove from busy list ++ pthread_mutex_lock(&m_omx_output_mutex); ++ assert(m_omx_output_busy > 0); ++ m_omx_output_busy--; ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ ReturnOpenMaxBuffer(buffer); ++ bool done = false; ++ pthread_mutex_lock(&m_omx_output_mutex); ++ if (m_finished && !m_omx_output_busy) ++ done = true; ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ if (done) ++ m_myself.reset(); ++ #if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s %p (%p) dts_queue(%d) ready_queue(%d) busy_queue(%d) done:%d", CLASSNAME, __func__, buffer, buffer->mmal_buffer, m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy, done); ++ #endif ++ delete buffer; ++} + +- // transition decoder component from idle to loaded +- omx_err = SetStateForComponent(OMX_StateLoaded); +- if (omx_err) +- CLog::Log(LOGERROR, +- "%s::%s - setting OMX_StateLoaded failed with omx_err(0x%x)\n", +- CLASSNAME, __func__, omx_err); ++bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) ++{ ++ //CLog::Log(LOGDEBUG, "%s::%s - m_omx_output_busy=%d m_omx_output_ready.size()=%d", CLASSNAME, __func__, m_omx_output_busy, m_omx_output_ready.size()); ++ //CLog::Log(LOGDEBUG, "%s::%s - full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size()); + +- return omx_err; ++ if (!m_omx_output_ready.empty()) ++ { ++ COpenMaxVideoBuffer *buffer; ++ // fetch a output buffer and pop it off the ready list ++ pthread_mutex_lock(&m_omx_output_mutex); ++ buffer = m_omx_output_ready.front(); ++ m_omx_output_ready.pop(); ++ pthread_mutex_unlock(&m_omx_output_mutex); ++ ++ assert(buffer->mmal_buffer); ++ memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture); ++ pDvdVideoPicture->format = RENDER_FMT_OMXEGL; ++ pDvdVideoPicture->openMaxBuffer = buffer; ++ pDvdVideoPicture->color_range = 0; ++ pDvdVideoPicture->color_matrix = 4; ++ pDvdVideoPicture->iWidth = buffer->width ? buffer->width : m_decoded_width; ++ pDvdVideoPicture->iHeight = buffer->height ? buffer->height : m_decoded_height; ++ pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth; ++ pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; ++ //CLog::Log(LOGDEBUG, "%s::%s - %dx%d %dx%d %dx%d %dx%d %d,%d %f,%f", CLASSNAME, __func__, pDvdVideoPicture->iWidth, pDvdVideoPicture->iHeight, pDvdVideoPicture->iDisplayWidth, pDvdVideoPicture->iDisplayHeight, m_decoded_width, m_decoded_height, buffer->width, buffer->height, m_forced_aspect_ratio, m_hints.forced_aspect, buffer->m_aspect_ratio, m_hints.aspect); ++ ++ if (buffer->m_aspect_ratio > 0.0 && !m_forced_aspect_ratio) ++ { ++ pDvdVideoPicture->iDisplayWidth = ((int)lrint(pDvdVideoPicture->iHeight * buffer->m_aspect_ratio)) & -3; ++ if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth) ++ { ++ pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth; ++ pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / buffer->m_aspect_ratio)) & -3; ++ } ++ } ++ ++ // timestamp is in microseconds + pDvdVideoPicture->dts = buffer->dts; - pDvdVideoPicture->pts = FromOMXTime(buffer->omx_buffer->nTimeStamp); - pDvdVideoPicture->openMaxBuffer->Acquire(); - pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; - if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_PTS_INVALID) - pDvdVideoPicture->pts = DVD_NOPTS_VALUE; - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__, -+ CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x frame:%d openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__, - pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6, -- pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id); -+ pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, (int)buffer->omx_buffer->pMarkData, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id); - #endif - assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED))); - } -@@ -956,6 +970,12 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture) - CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__); - return false; - } ++ pDvdVideoPicture->pts = buffer->mmal_buffer->pts == MMAL_TIME_UNKNOWN || buffer->mmal_buffer->pts == 0 ? DVD_NOPTS_VALUE : buffer->mmal_buffer->pts; ++ ++ pDvdVideoPicture->openMaxBuffer->Acquire(); ++ pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p mmal_buffer:%p", CLASSNAME, __func__, ++ pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6, ++ pDvdVideoPicture->iFlags, buffer->mmal_buffer->flags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->mmal_buffer); ++#endif ++ assert(!(buffer->mmal_buffer->flags & MMAL_BUFFER_HEADER_FLAG_DECODEONLY)); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__); ++ return false; ++ } + + if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE) + m_decoderPts = pDvdVideoPicture->pts; + else + m_decoderPts = pDvdVideoPicture->dts; // xxx is DVD_NOPTS_VALUE better? + - return true; - } - -@@ -970,25 +990,56 @@ bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture) - return true; - } - ++ return true; ++} ++ ++bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture) ++{ ++#if defined(OMX_DEBUG_VERBOSE) ++ CLog::Log(LOGDEBUG, "%s::%s - %p (%p)", CLASSNAME, __func__, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer ? pDvdVideoPicture->openMaxBuffer->mmal_buffer : 0); ++#endif ++ if (pDvdVideoPicture->format == RENDER_FMT_OMXEGL) ++ { ++ pDvdVideoPicture->openMaxBuffer->Release(); ++ } ++ memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture); ++ return true; ++} ++ +bool COpenMaxVideo::GetCodecStats(double &pts, int &droppedPics) +{ + pts = m_decoderPts; + droppedPics = m_droppedPics; + m_droppedPics = 0; +#if defined(OMX_DEBUG_VERBOSE) -+ CLog::Log(LOGDEBUG, "%s::%s - pts:%.0f droppedPics:%d", CLASSNAME, __func__, pts, droppedPics); ++ //CLog::Log(LOGDEBUG, "%s::%s - pts:%.0f droppedPics:%d", CLASSNAME, __func__, pts, droppedPics); +#endif + return true; -+} -+ - // DecoderFillBufferDone -- OpenMax output buffer has been filled - OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone( - OMX_HANDLETYPE hComponent, - OMX_BUFFERHEADERTYPE* pBuffer) - { - COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate; -+ bool skipDeinterlaceFields = m_skipDeinterlaceFields || g_windowManager.HasDialogOnScreen(); - - #if defined(OMX_DEBUG_VERBOSE) -- CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x", -- CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags); -+ CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x frame:%d win:%x", -+ CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags, (int)buffer->omx_buffer->pMarkData, skipDeinterlaceFields); - #endif - - assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED))); -- // queue output omx buffer to ready list. -- pthread_mutex_lock(&m_omx_output_mutex); -- buffer->m_aspect_ratio = m_aspect_ratio; -- m_omx_output_ready.push(buffer); -- pthread_mutex_unlock(&m_omx_output_mutex); - -+ -+ // flags have OMX_BUFFERFLAG_FIRST_FIELD set if this is a direct result of a submitted frame, -+ // clear for second field of deinterlaced frame. They are zero when frame is returned due to a flush. -+#ifdef DTS_QUEUE -+ if ((!m_deinterlace || (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD)) && buffer->omx_buffer->nFlags) -+ { -+ pthread_mutex_lock(&m_omx_output_mutex); -+ assert(!m_dts_queue.empty()); -+ buffer->dts = m_dts_queue.front(); -+ m_dts_queue.pop(); -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ } -+#endif -+ if (m_drop_state || (m_deinterlace && skipDeinterlaceFields && !(buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD))) -+ { -+ ReturnOpenMaxBuffer(buffer); -+ } -+ else -+ { -+ buffer->m_aspect_ratio = m_aspect_ratio; -+ pthread_mutex_lock(&m_omx_output_mutex); -+ m_omx_output_ready.push(buffer); -+ pthread_mutex_unlock(&m_omx_output_mutex); -+ } - return OMX_ErrorNone; } diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -index f234f6d..adf53b5 100644 +index e06c41d..f931419 100644 --- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h +++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h -@@ -57,6 +57,7 @@ class COpenMaxVideoBuffer +@@ -21,93 +21,136 @@ + + #if defined(HAVE_LIBOPENMAX) + +-#include "OpenMax.h" +-#include +-#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cores/dvdplayer/DVDStreamInfo.h" ++#include "DVDVideoCodec.h" ++#include "threads/Event.h" ++#include "xbmc/settings/VideoSettings.h" ++ ++#include ++#include ++#include ++#include "utils/StdString.h" ++#include "guilib/Geometry.h" ++#include "rendering/RenderSystem.h" ++ ++class COpenMaxVideo; ++typedef boost::shared_ptr OpenMaxVideoPtr; + + // an omx egl video frame +-typedef struct OpenMaxVideoBuffer { +- OMX_BUFFERHEADERTYPE *omx_buffer; ++class COpenMaxVideoBuffer ++{ ++public: ++ COpenMaxVideoBuffer(COpenMaxVideo *omv); ++ virtual ~COpenMaxVideoBuffer(); ++ ++ MMAL_BUFFER_HEADER_T *mmal_buffer; + int width; int height; - float m_aspect_ratio; ++ float m_aspect_ratio; int index; + double dts; ++ uint32_t m_changed_count; ++ // reference counting ++ COpenMaxVideoBuffer* Acquire(); ++ long Release(); ++ COpenMaxVideo *m_omv; ++ long m_refs; ++private: ++}; - // used for egl based rendering if active - EGLImageKHR egl_image; -@@ -87,6 +88,7 @@ class COpenMaxVideo - virtual unsigned GetAllowedReferences() { return 2; } - virtual void SetDropState(bool bDrop); - virtual const char* GetName(void) { return (const char*)m_pFormatName; } +- // used for egl based rendering if active +- EGLImageKHR egl_image; +- GLuint texture_id; +-} OpenMaxVideoBuffer; +- +-class COpenMaxVideo : public COpenMax ++class COpenMaxVideo + { ++ typedef struct omx_demux_packet { ++ uint8_t *buff; ++ int size; ++ double dts; ++ double pts; ++ } omx_demux_packet; ++ + public: + COpenMaxVideo(); + virtual ~COpenMaxVideo(); + + // Required overrides +- bool Open(CDVDStreamInfo &hints); +- void Close(void); +- int Decode(uint8_t *pData, int iSize, double dts, double pts); +- void Reset(void); +- bool GetPicture(DVDVideoPicture *pDvdVideoPicture); +- void SetDropState(bool bDrop); +-protected: +- void QueryCodec(void); +- OMX_ERRORTYPE PrimeFillBuffers(void); +- OMX_ERRORTYPE AllocOMXInputBuffers(void); +- OMX_ERRORTYPE FreeOMXInputBuffers(bool wait); +- OMX_ERRORTYPE AllocOMXOutputBuffers(void); +- OMX_ERRORTYPE FreeOMXOutputBuffers(bool wait); +- static void CallbackAllocOMXEGLTextures(void*); +- OMX_ERRORTYPE AllocOMXOutputEGLTextures(void); +- static void CallbackFreeOMXEGLTextures(void*); +- OMX_ERRORTYPE FreeOMXOutputEGLTextures(bool wait); +- +- // TODO Those should move into the base class. After start actions can be executed by callbacks. +- OMX_ERRORTYPE StartDecoder(void); +- OMX_ERRORTYPE StopDecoder(void); ++ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself); ++ virtual void Dispose(void); ++ virtual int Decode(uint8_t *pData, int iSize, double dts, double pts); ++ virtual void Reset(void); ++ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture); ++ virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture); ++ virtual unsigned GetAllowedReferences() { return 2; } ++ virtual void SetDropState(bool bDrop); ++ virtual const char* GetName(void) { return (const char*)m_pFormatName; } + virtual bool GetCodecStats(double &pts, int &droppedPics); // OpenMax decoder callback routines. - OMX_ERRORTYPE DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer); -@@ -142,10 +144,11 @@ class COpenMaxVideo +- virtual OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, +- OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData); +- virtual OMX_ERRORTYPE DecoderEmptyBufferDone( +- OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer); +- virtual OMX_ERRORTYPE DecoderFillBufferDone( +- OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader); ++ void ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer); ++ void Recycle(MMAL_BUFFER_HEADER_T *buffer); ++ ++ // MMAL decoder callback routines. ++ void dec_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); ++ void dec_control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); ++ uint32_t m_changed_count; ++ uint32_t m_changed_count_dec; - bool m_deinterlace; - EDEINTERLACEMODE m_deinterlace_request; -- bool m_deinterlace_second_field; +- // EGL Resources +- EGLDisplay m_egl_display; +- EGLContext m_egl_context; ++protected: ++ void QueryCodec(void); ++ void ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer); ++ bool CreateDeinterlace(); ++ bool DestroyDeinterlace(); + + // Video format +- DVDVideoPicture m_videobuffer; + bool m_drop_state; + int m_decoded_width; + int m_decoded_height; ++ unsigned int m_egl_buffer_count; ++ bool m_finished; ++ float m_aspect_ratio; ++ bool m_forced_aspect_ratio; ++ const char *m_pFormatName; ++ OpenMaxVideoPtr m_myself; + + std::queue m_dts_queue; + std::queue m_demux_queue; + +- // OpenMax input buffers (demuxer packets) +- pthread_mutex_t m_omx_input_mutex; +- std::queue m_omx_input_avaliable; +- std::vector m_omx_input_buffers; +- bool m_omx_input_eos; +- int m_omx_input_port; +- //sem_t *m_omx_flush_input; +- CEvent m_input_consumed_event; - - bool m_startframe; + // OpenMax output buffers (video frames) + pthread_mutex_t m_omx_output_mutex; +- std::queue m_omx_output_busy; +- std::queue m_omx_output_ready; +- std::vector m_omx_output_buffers; +- bool m_omx_output_eos; +- int m_omx_output_port; +- //sem_t *m_omx_flush_output; - +- bool m_portChanging; +- +- volatile bool m_videoplayback_done; ++ int m_omx_output_busy; ++ std::queue m_omx_output_ready; ++ std::vector m_omx_output_buffers; ++ ++ // initialize OpenMax and get decoder component ++ bool Initialize( const CStdString &decoder_name); ++ void PortSettingsChanged(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); ++ bool SendCodecConfigData(); ++ ++ CDVDStreamInfo m_hints; ++ // Components ++ //MMAL_INTERLACETYPE_T m_interlace_mode; ++ bool m_startframe; + unsigned int m_decode_frame_number; + double m_decoderPts; + unsigned int m_droppedPics; -+ bool m_skipDeinterlaceFields; - bool PortSettingsChanged(); - bool SendDecoderConfig(uint8_t *extradata, int extrasize); - bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize); --- -2.0.4 - - -From 47b4c152cb3e710952f4549f327d5959045ee6a1 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 11 Apr 2014 16:12:27 +0100 -Subject: [PATCH 57/98] [omxplayer] Add ability to log more timestamp info in - extra debug settings - ---- - language/English/strings.po | 5 ++++ - xbmc/commons/ilog.h | 1 + - xbmc/cores/omxplayer/OMXPlayer.cpp | 52 ++++++++++++++++----------------- - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 8 ++--- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 9 +++--- - xbmc/settings/AdvancedSettings.cpp | 3 ++ - 6 files changed, 44 insertions(+), 34 deletions(-) - -diff --git a/language/English/strings.po b/language/English/strings.po -index 6e7c98c..1c3b6a6 100755 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -2886,6 +2886,11 @@ msgctxt "#679" - msgid "Verbose logging for CEC library" - msgstr "" - -+#: xbmc/settings/AdvancedSettings.cpp -+msgctxt "#697" -+msgid "Verbose logging for OMXPLAYER" -+msgstr "" + - #empty strings from id 680 to 699 - - msgctxt "#700" -diff --git a/xbmc/commons/ilog.h b/xbmc/commons/ilog.h -index 4bf5d83..3fb7cc3 100644 ---- a/xbmc/commons/ilog.h -+++ b/xbmc/commons/ilog.h -@@ -53,6 +53,7 @@ - #define LOGAIRTUNES (1 << (LOGMASKBIT + 8)) - #define LOGUPNP (1 << (LOGMASKBIT + 9)) - #define LOGCEC (1 << (LOGMASKBIT + 10)) -+#define LOGOMXPLAYER (1 << (LOGMASKBIT+11)) - - #ifdef __GNUC__ - #define ATTRIB_LOG_FORMAT __attribute__((format(printf,3,4))) -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index f1c9931..62b671d 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -1545,27 +1545,28 @@ void CDVDPlayer::Process() - m_video_fifo = (int)(100.0*(m_dvdPlayerVideo.GetDecoderBufferSize()-m_dvdPlayerVideo.GetDecoderFreeSpace())/m_dvdPlayerVideo.GetDecoderBufferSize()); - m_audio_fifo = (int)(100.0*audio_fifo/m_dvdPlayerAudio.GetCacheTotal()); - -- #ifdef _DEBUG -- static unsigned count; -- if ((count++ & 7) == 0) -+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER)) - { -- char response[80]; -- if (m_dvdPlayerVideo.GetDecoderBufferSize() && m_dvdPlayerAudio.GetCacheTotal()) -- vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d", -- m_video_fifo, -- (int)(100.0*video_fifo/m_dvdPlayerAudio.GetCacheTotal()), -- 0, 100); -- if (m_dvdPlayerAudio.GetCacheTotal()) -- vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d", -- m_audio_fifo, -- (int)(100.0*m_dvdPlayerAudio.GetDelay()/m_dvdPlayerAudio.GetCacheTotal()), -- 0, 100); -- vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d", -- m_dvdPlayerVideo.GetLevel(), 0, 0, 100); -- vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d", -- m_dvdPlayerAudio.GetLevel(), 0, 0, 100); -+ static unsigned count; -+ if ((count++ & 7) == 0) -+ { -+ char response[80]; -+ if (m_dvdPlayerVideo.GetDecoderBufferSize() && m_dvdPlayerAudio.GetCacheTotal()) -+ vc_gencmd(response, sizeof response, "render_bar 4 video_fifo %d %d %d %d", -+ m_video_fifo, -+ (int)(100.0*video_fifo/m_dvdPlayerAudio.GetCacheTotal()), -+ 0, 100); -+ if (m_dvdPlayerAudio.GetCacheTotal()) -+ vc_gencmd(response, sizeof response, "render_bar 5 audio_fifo %d %d %d %d", -+ m_audio_fifo, -+ (int)(100.0*m_dvdPlayerAudio.GetDelay()/m_dvdPlayerAudio.GetCacheTotal()), -+ 0, 100); -+ vc_gencmd(response, sizeof response, "render_bar 6 video_queue %d %d %d %d", -+ m_dvdPlayerVideo.GetLevel(), 0, 0, 100); -+ vc_gencmd(response, sizeof response, "render_bar 7 audio_queue %d %d %d %d", -+ m_dvdPlayerAudio.GetLevel(), 0, 0, 100); -+ } - } -- #endif - if (audio_pts != DVD_NOPTS_VALUE) - { - audio_fifo_low = m_HasAudio && audio_fifo < threshold; -@@ -1581,13 +1582,12 @@ void CDVDPlayer::Process() - if (!m_HasVideo && m_HasAudio) - video_fifo_high = true; - -- #ifdef _DEBUG -- CLog::Log(LOGDEBUG, "%s - M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", __FUNCTION__, -- m_stamp*1e-6, m_av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6, m_av_clock.OMXIsPaused(), bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL), -- audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_threshold, -- audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, -- m_dvdPlayerAudio.GetLevel(), m_dvdPlayerVideo.GetLevel(), m_dvdPlayerAudio.GetDelay(), (float)m_dvdPlayerAudio.GetCacheTotal()); -- #endif -+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER)) -+ CLog::Log(LOGDEBUG, "%s - M:%.6f-%.6f (A:%.6f V:%.6f) PEF:%d%d%d S:%.2f A:%.2f V:%.2f/T:%.2f (A:%d%d V:%d%d) A:%d%% V:%d%% (%.2f,%.2f)", __FUNCTION__, -+ m_stamp*1e-6, m_av_clock.OMXClockAdjustment()*1e-6, audio_pts*1e-6, video_pts*1e-6, m_av_clock.OMXIsPaused(), bOmxSentEOFs, not_accepts_data, m_playSpeed * (1.0f/DVD_PLAYSPEED_NORMAL), -+ audio_pts == DVD_NOPTS_VALUE ? 0.0:audio_fifo, video_pts == DVD_NOPTS_VALUE ? 0.0:video_fifo, m_threshold, -+ audio_fifo_low, audio_fifo_high, video_fifo_low, video_fifo_high, -+ m_dvdPlayerAudio.GetLevel(), m_dvdPlayerVideo.GetLevel(), m_dvdPlayerAudio.GetDelay(), (float)m_dvdPlayerAudio.GetCacheTotal()); - - if (TP(m_playSpeed)) - { -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -index c1b7a0d..37b544c 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -@@ -364,10 +364,10 @@ void OMXPlayerAudio::Process() - DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); - bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); - -- #ifdef _DEBUG -- CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts, -- (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate); -- #endif -+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER)) -+ CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts, -+ (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate); ++ MMAL_COMPONENT_T *m_dec; ++ MMAL_PORT_T *m_dec_input; ++ MMAL_PORT_T *m_dec_output; ++ MMAL_POOL_T *m_dec_input_pool; ++ MMAL_POOL_T *m_dec_output_pool; + - if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop)) - { - // we are not running until something is cached in output device -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 0514e78..811f087 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -42,6 +42,7 @@ - #include "DVDOverlayRenderer.h" - #include "settings/DisplaySettings.h" - #include "settings/Settings.h" -+#include "settings/AdvancedSettings.h" - #include "settings/MediaSettings.h" - #include "cores/VideoRenderers/RenderFormats.h" - #include "cores/VideoRenderers/RenderFlags.h" -@@ -450,10 +451,10 @@ void OMXPlayerVideo::Process() - DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket(); - bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop(); - -- #ifdef _DEBUG -- CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts, -- (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0); -- #endif -+ if (g_advancedSettings.CanLogComponent(LOGOMXPLAYER)) -+ CLog::Log(LOGINFO, "Video: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d\n", pPacket->dts, pPacket->pts, -+ (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, 0); ++ MMAL_ES_FORMAT_T *m_es_format; ++ MMAL_COMPONENT_T *m_deint; ++ MMAL_CONNECTION_T *m_deint_connection; + - if (m_messageQueue.GetDataSize() == 0 - || m_speed < 0) - { -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 5f3f2d8..56f9783 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -1386,6 +1386,9 @@ void CAdvancedSettings::SettingOptionsLoggingComponentsFiller(const CSetting *se - #ifdef HAVE_LIBCEC - list.push_back(std::make_pair(g_localizeStrings.Get(679), LOGCEC)); - #endif -+#ifdef TARGET_RASPBERRY_PI -+ list.push_back(std::make_pair(g_localizeStrings.Get(697), LOGOMXPLAYER)); -+#endif - } - - void CAdvancedSettings::setExtraLogLevel(const std::vector &components) --- -2.0.4 - - -From f6fada00d9cbed53453bbd0630e97109da388c8e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 7 Apr 2014 23:13:55 +0100 -Subject: [PATCH 58/98] [omxplayer] Add ability to dump out audio/video data - for later debugging - ---- - language/English/strings.po | 10 ++++++++ - xbmc/commons/ilog.h | 2 ++ - xbmc/cores/omxplayer/OMXAudio.cpp | 49 ++++++++++++++++++++++++++++++++++++++ - xbmc/cores/omxplayer/OMXVideo.cpp | 47 ++++++++++++++++++++++++++++++++++++ - xbmc/settings/AdvancedSettings.cpp | 4 ++++ - 5 files changed, 112 insertions(+) - -diff --git a/language/English/strings.po b/language/English/strings.po -index 1c3b6a6..a3ead30 100755 ---- a/language/English/strings.po -+++ b/language/English/strings.po -@@ -2891,6 +2891,16 @@ msgctxt "#697" - msgid "Verbose logging for OMXPLAYER" - msgstr "" - -+#: xbmc/settings/AdvancedSettings.cpp -+msgctxt "#698" -+msgid "Dump video frames to debug file" -+msgstr "" -+ -+#: xbmc/settings/AdvancedSettings.cpp -+msgctxt "#699" -+msgid "Dump audio frames to debug file" -+msgstr "" -+ - #empty strings from id 680 to 699 - - msgctxt "#700" -diff --git a/xbmc/commons/ilog.h b/xbmc/commons/ilog.h -index 3fb7cc3..4d722a0 100644 ---- a/xbmc/commons/ilog.h -+++ b/xbmc/commons/ilog.h -@@ -54,6 +54,8 @@ - #define LOGUPNP (1 << (LOGMASKBIT + 9)) - #define LOGCEC (1 << (LOGMASKBIT + 10)) - #define LOGOMXPLAYER (1 << (LOGMASKBIT+11)) -+#define LOGDUMPVIDEO (1 << (LOGMASKBIT+12)) -+#define LOGDUMPAUDIO (1 << (LOGMASKBIT+13)) - - #ifdef __GNUC__ - #define ATTRIB_LOG_FORMAT __attribute__((format(printf,3,4))) -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp -index c0c3a3f..5068017 100644 ---- a/xbmc/cores/omxplayer/OMXAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp -@@ -60,6 +60,49 @@ static const uint16_t AC3FSCod [] = {48000, 44100, 32000, 0}; - - static const uint16_t DTSFSCod [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0}; - -+//#define DEBUG_PLAYBACK -+static void dump_omx_buffer(OMX_BUFFERHEADERTYPE *omx_buffer) -+{ -+ if (!(g_advancedSettings.CanLogComponent(LOGDUMPAUDIO))) -+ return; -+ static FILE *fp; -+ if (!omx_buffer) -+ { -+ if (fp) -+ { -+ fclose(fp); -+ fp = NULL; -+ } -+ return; -+ } -+ if (!fp) -+ { -+ char filename[1024]; -+ strcpy(filename, g_advancedSettings.m_logFolder.c_str()); -+ strcat(filename, "audio.dat"); -+#ifdef DEBUG_PLAYBACK -+ fp = fopen(filename, "rb"); -+#else -+ fp = fopen(filename, "wb"); -+#endif -+ } -+ if (fp) -+ { -+#ifdef DEBUG_PLAYBACK -+ OMX_BUFFERHEADERTYPE omx = {0}; -+ int s = fread(&omx, sizeof omx, 1, fp); -+ omx_buffer->nFilledLen = omx.nFilledLen; -+ omx_buffer->nFlags = omx.nFlags; -+ omx_buffer->nTimeStamp = omx.nTimeStamp; -+ if (s==1) -+ fread(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp); -+#else -+ if (fwrite(omx_buffer, sizeof *omx_buffer, 1, fp) == 1) -+ fwrite(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp); -+#endif -+ } -+} -+ - ////////////////////////////////////////////////////////////////////// - // Construction/Destruction - ////////////////////////////////////////////////////////////////////// -@@ -867,6 +910,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo - memcpy((unsigned char *)omx_buffer->pBuffer, &m_wave_header, omx_buffer->nFilledLen); - omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME; - -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err != OMX_ErrorNone) - { -@@ -899,6 +943,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo - memcpy((unsigned char *)omx_buffer->pBuffer, m_extradata, omx_buffer->nFilledLen); - omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME; - -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err != OMX_ErrorNone) - { -@@ -935,6 +980,8 @@ bool COMXAudio::Deinitialize() - { - CSingleLock lock (m_critSection); - -+ dump_omx_buffer(NULL); -+ - if ( m_omx_tunnel_clock_analog.IsInitialized() ) - m_omx_tunnel_clock_analog.Deestablish(); - if ( m_omx_tunnel_clock_hdmi.IsInitialized() ) -@@ -1227,6 +1274,7 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt - int nRetry = 0; - while(true) - { -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err == OMX_ErrorNone) - { -@@ -1493,6 +1541,7 @@ void COMXAudio::SubmitEOS() - - omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN; - -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err != OMX_ErrorNone) - { -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index b9256ea..7759da8 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -63,6 +63,49 @@ - - #define MAX_TEXT_LENGTH 1024 - -+//#define DEBUG_PLAYBACK -+static void dump_omx_buffer(OMX_BUFFERHEADERTYPE *omx_buffer) -+{ -+ if (!(g_advancedSettings.CanLogComponent(LOGDUMPVIDEO))) -+ return; -+ static FILE *fp; -+ if (!omx_buffer) -+ { -+ if (fp) -+ { -+ fclose(fp); -+ fp = NULL; -+ } -+ return; -+ } -+ if (!fp) -+ { -+ char filename[1024]; -+ strcpy(filename, g_advancedSettings.m_logFolder.c_str()); -+ strcat(filename, "video.dat"); -+#ifdef DEBUG_PLAYBACK -+ fp = fopen(filename, "rb"); -+#else -+ fp = fopen(filename, "wb"); -+#endif -+ } -+ if (fp) -+ { -+#ifdef DEBUG_PLAYBACK -+ OMX_BUFFERHEADERTYPE omx = {0}; -+ int s = fread(&omx, sizeof omx, 1, fp); -+ omx_buffer->nFilledLen = omx.nFilledLen; -+ omx_buffer->nFlags = omx.nFlags; -+ omx_buffer->nTimeStamp = omx.nTimeStamp; -+ if (s==1) -+ fread(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp); -+#else -+ if (fwrite(omx_buffer, sizeof *omx_buffer, 1, fp) == 1) -+ fwrite(omx_buffer->pBuffer, omx_buffer->nFilledLen, 1, fp); -+#endif -+ } -+} -+ - COMXVideo::COMXVideo() : m_video_codec_name("") - { - m_is_open = false; -@@ -118,6 +161,7 @@ bool COMXVideo::SendDecoderConfig() - memcpy((unsigned char *)omx_buffer->pBuffer, m_extradata, omx_buffer->nFilledLen); - omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME; - -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err != OMX_ErrorNone) - { -@@ -707,6 +751,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de - void COMXVideo::Close() - { - CSingleLock lock (m_critSection); -+ dump_omx_buffer(NULL); - m_omx_tunnel_clock.Deestablish(); - m_omx_tunnel_decoder.Deestablish(); - if(m_deinterlace) -@@ -801,6 +846,7 @@ int COMXVideo::Decode(uint8_t *pData, int iSize, double pts) - int nRetry = 0; - while(true) - { -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err == OMX_ErrorNone) - { -@@ -930,6 +976,7 @@ void COMXVideo::SubmitEOS() - - omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN; - -+ dump_omx_buffer(omx_buffer); - omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer); - if (omx_err != OMX_ErrorNone) - { -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 56f9783..627080b 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -1389,6 +1389,10 @@ void CAdvancedSettings::SettingOptionsLoggingComponentsFiller(const CSetting *se - #ifdef TARGET_RASPBERRY_PI - list.push_back(std::make_pair(g_localizeStrings.Get(697), LOGOMXPLAYER)); - #endif -+#ifdef TARGET_RASPBERRY_PI -+ list.push_back(std::make_pair(g_localizeStrings.Get(698), LOGDUMPVIDEO)); -+ list.push_back(std::make_pair(g_localizeStrings.Get(699), LOGDUMPAUDIO)); -+#endif - } - - void CAdvancedSettings::setExtraLogLevel(const std::vector &components) --- -2.0.4 - - -From 3476fc5f3dad5b268d66c16aa4200700da87ba5d Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 28 May 2014 18:30:51 +0100 -Subject: [PATCH 59/98] [omxcodec] Reduce GPU memory use by 2 video frames - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index 612ae21..494fdf5 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -308,6 +308,20 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM - return false; - } - -+ { -+ // as we aren't tunnelled to display, we can save memory by setting extrabuffers to 0 -+ OMX_PARAM_U32TYPE extra_buffers; -+ OMX_INIT_STRUCTURE(extra_buffers); -+ extra_buffers.nU32 = 0; -+ -+ omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmExtraBuffers, &extra_buffers); -+ if(omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmExtraBuffers omx_err(0x%08x)\n", omx_err); -+ return false; -+ } -+ } -+ - // request portsettingschanged on aspect ratio change - OMX_CONFIG_REQUESTCALLBACKTYPE notifications; - OMX_INIT_STRUCTURE(notifications); --- -2.0.4 - - -From 1a330ea289da487c224b436ad58f84161d9accd2 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 30 May 2014 14:58:43 +0100 -Subject: [PATCH 60/98] [settings] Experiment: Report DESKTOP resolution in - video settings - ---- - xbmc/settings/DisplaySettings.cpp | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/xbmc/settings/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp -index bb31f15..eae549b 100644 ---- a/xbmc/settings/DisplaySettings.cpp -+++ b/xbmc/settings/DisplaySettings.cpp -@@ -650,6 +650,9 @@ void CDisplaySettings::SettingOptionsResolutionsFiller(const CSetting *setting, - vector resolutions = g_Windowing.ScreenResolutions(info.iScreen, info.fRefreshRate); - for (vector::const_iterator resolution = resolutions.begin(); resolution != resolutions.end(); ++resolution) - { -+if (resolution->ResInfo_Index == RES_DESKTOP) -+ list.push_back(make_pair(StringUtils::Format("DESKTOP"), resolution->ResInfo_Index)); -+else - list.push_back(make_pair( - StringUtils::Format("%dx%d%s", resolution->width, resolution->height, - ModeFlagsToString(resolution->flags, false).c_str()), --- -2.0.4 - - -From b3ea9fc728aa1b4741b42051aa28d6dc4753319b Mon Sep 17 00:00:00 2001 -From: Matthias Kortstiege -Date: Sun, 1 Jun 2014 18:47:20 +0200 -Subject: [PATCH 61/98] changed: avoid useless filesytem io while searching for - subtitles - ---- - xbmc/Util.cpp | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp -index 042c3f7..d8c50e8 100644 ---- a/xbmc/Util.cpp -+++ b/xbmc/Util.cpp -@@ -1982,7 +1982,7 @@ void CUtil::ScanForExternalSubtitles(const std::string& strMovie, std::vector -Date: Mon, 30 Dec 2013 12:02:14 +0000 -Subject: [PATCH 62/98] [rbp] Hardware accelerated resampling - -This replaces the format conversion, up/down mixing and resampling code from ActiveAE with a GPU accelerated version. -Should significantly reduce CPU when using paplayer or dvdplayer. - -Requires updated firmware ---- - .../Engines/ActiveAE/ActiveAEResample.cpp | 5 + - .../Engines/ActiveAE/ActiveAEResample.h | 8 + - .../Engines/ActiveAE/ActiveAEResamplePi.cpp | 601 +++++++++++++++++++++ - .../Engines/ActiveAE/ActiveAEResamplePi.h | 62 +++ - xbmc/cores/AudioEngine/Makefile.in | 1 + - xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 14 +- - xbmc/linux/OMXCore.cpp | 4 +- - 7 files changed, 686 insertions(+), 9 deletions(-) - create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp - create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h - -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp -index 03946c3..5feeefb 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp -@@ -18,6 +18,10 @@ - * - */ - -+#include "system.h" -+ -+#if !defined(TARGET_RASPBERRY_PI) -+ - #include "ActiveAEResample.h" - #include "utils/log.h" - -@@ -360,3 +364,4 @@ int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layo - { - return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); - } -+#endif -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h -index a471e02..5d37cc7 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h -@@ -19,6 +19,8 @@ - * - */ - -+#include "system.h" -+ - #include "cores/AudioEngine/Utils/AEChannelInfo.h" - #include "cores/AudioEngine/Utils/AEAudioFormat.h" - #include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h" -@@ -29,6 +31,10 @@ extern "C" { - #include "libswresample/swresample.h" - } - -+#if defined(TARGET_RASPBERRY_PI) -+#include "ActiveAEResamplePi.h" -+#else -+ - namespace ActiveAE - { - -@@ -63,3 +69,5 @@ class CActiveAEResample ++ MMAL_FOURCC_T m_codingType; ++ bool change_dec_output_format(); }; + // defined(HAVE_LIBOPENMAX) +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 3bfa7f1..8b60288 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -194,7 +194,7 @@ bool CDVDPlayerVideo::OpenStream( CDVDStreamInfo &hint ) + if(hint.flags & AV_DISPOSITION_ATTACHED_PIC) + return false; + +- CLog::Log(LOGNOTICE, "Creating video codec with codec id: %i", hint.codec); ++ CLog::Log(LOGNOTICE, "Creating video codec with codec id: %i %dx%d", hint.codec, hint.width, hint.height); + CDVDVideoCodec* codec = CDVDFactoryCodec::CreateVideoCodec(hint, surfaces, formats); + if(!codec) + { + +From 4bbd1790c53efb19d551d13e366cdd00242d06e1 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 12 Aug 2014 00:31:36 +0100 +Subject: [PATCH 33/77] [omxcodec] Fix for stills with hardware codec + + +From 3e0e029ac15454d5a662f37ef875e8fc33a518cc Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 2 Aug 2014 17:47:38 +0100 +Subject: [PATCH 34/77] [VideoReferenceClock] Add OMX support + +--- + xbmc/linux/RBP.cpp | 34 ++++++++++++++++++++++++ + xbmc/linux/RBP.h | 3 +++ + xbmc/video/VideoReferenceClock.cpp | 53 ++++++++++++++++++++++++++++++++++++++ + xbmc/video/VideoReferenceClock.h | 6 +++++ + 4 files changed, 96 insertions(+) + +diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp +index 73a42c4..11376fc 100644 +--- a/xbmc/linux/RBP.cpp ++++ b/xbmc/linux/RBP.cpp +@@ -32,6 +32,7 @@ CRBP::CRBP() + m_omx_initialized = false; + m_DllBcmHost = new DllBcmHost(); + m_OMX = new COMXCore(); ++ m_element = 0; } + + CRBP::~CRBP() +@@ -53,6 +54,9 @@ bool CRBP::Initialize() + + m_DllBcmHost->bcm_host_init(); + ++ uint32_t vc_image_ptr; ++ m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr ); + -+#endif -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -new file mode 100644 -index 0000000..9a1e549 ---- /dev/null -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -@@ -0,0 +1,601 @@ -+/* -+ * Copyright (C) 2010-2013 Team XBMC -+ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ + m_omx_initialized = m_OMX->Initialize(); + if(!m_omx_initialized) + return false; +@@ -156,6 +160,36 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + return image; + } + ++void CRBP::WaitVsync(void) ++{ ++ DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); + -+#include "system.h" ++ VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 }; ++ VC_RECT_T src_rect; ++ VC_RECT_T dst_rect; ++ vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 ); ++ vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 ); + -+#if defined(TARGET_RASPBERRY_PI) ++ if (m_element) ++ vc_dispmanx_element_remove( update, m_element ); + -+#include "ActiveAEResample.h" -+#include "linux/RBP.h" -+#include "settings/Settings.h" -+#include "utils/log.h" ++ m_element = vc_dispmanx_element_add( update, ++ display, ++ 2000, // layer ++ &dst_rect, ++ m_resource, ++ &src_rect, ++ DISPMANX_PROTECTION_NONE, ++ &alpha, ++ NULL, // clamp ++ (DISPMANX_TRANSFORM_T)0 ); + -+extern "C" { -+#include "libavutil/channel_layout.h" -+#include "libavutil/opt.h" -+#include "libswresample/swresample.h" ++ vc_dispmanx_update_submit_sync(update); ++ vc_dispmanx_display_close( display ); +} + -+//#define DEBUG_VERBOSE + -+#define CLASSNAME "CActiveAEResamplePi" -+ -+#define BUFFERSIZE (32*1024*2*8) -+ -+//#define BENCHMARKING -+#ifdef BENCHMARKING -+#define LOGTIMEINIT(f) \ -+ struct timespec now; \ -+ uint64_t Start, End; \ -+ clock_gettime(CLOCK_MONOTONIC, &now); \ -+ Start = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \ -+ const char *_filename = f; -+ -+#define LOGTIME(n) \ -+ clock_gettime(CLOCK_MONOTONIC, &now); \ -+ End = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \ -+ CLog::Log(LOGNOTICE, "ActiveAE::%s %d - resample %s took %.0fms", __FUNCTION__, n, _filename, (End-Start)*1e-6); \ -+ Start=End; -+#else -+#define LOGTIMEINIT(f) -+#define LOGTIME(n) -+#endif -+ -+using namespace ActiveAE; -+ -+CActiveAEResample::CActiveAEResample() + void CRBP::Deinitialize() + { + if (m_omx_image_init) +diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h +index e9a2d5a..4fd18f3 100644 +--- a/xbmc/linux/RBP.h ++++ b/xbmc/linux/RBP.h +@@ -57,6 +57,7 @@ class CRBP + // stride can be null for packed output + unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true); + DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; } ++ void WaitVsync(); + + private: + DllBcmHost *m_DllBcmHost; +@@ -69,6 +70,8 @@ class CRBP + bool m_codec_mpg2_enabled; + bool m_codec_wvc1_enabled; + COMXCore *m_OMX; ++ DISPMANX_RESOURCE_HANDLE_T m_resource; ++ DISPMANX_ELEMENT_HANDLE_T m_element; + class DllLibOMXCore; + CCriticalSection m_critSection; + }; +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 6d84b60..916a15c 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -50,6 +50,9 @@ + #endif + #include "windowing/WindowingFactory.h" + #include "settings/AdvancedSettings.h" ++#elif defined(TARGET_RASPBERRY_PI) ++ #include "guilib/GraphicContext.h" ++ #include "linux/RBP.h" + #endif + + using namespace std; +@@ -177,6 +180,8 @@ void CVideoReferenceClock::Process() + CLog::Log(LOGDEBUG, "CVideoReferenceClock: compiled without RandR support"); + #elif defined(TARGET_WINDOWS) + CLog::Log(LOGDEBUG, "CVideoReferenceClock: only available on directx build"); ++#elif defined(TARGET_RASPBERRY_PI) ++ SetupSuccess = SetupOMX(); + #else + CLog::Log(LOGDEBUG, "CVideoReferenceClock: no implementation available"); + #endif +@@ -205,6 +210,8 @@ void CVideoReferenceClock::Process() + RunD3D(); + #elif defined(TARGET_DARWIN) + RunCocoa(); ++#elif defined(TARGET_RASPBERRY_PI) ++ RunOMX(); + #endif + + } +@@ -237,6 +244,8 @@ void CVideoReferenceClock::Process() + CleanupD3D(); + #elif defined(TARGET_DARWIN) + CleanupCocoa(); ++#elif defined(TARGET_RASPBERRY_PI) ++ CleanupOMX(); + #endif + if (!SetupSuccess) break; + } +@@ -863,6 +872,50 @@ void CVideoReferenceClock::VblankHandler(int64_t nowtime, double fps) + SendVblankSignal(); + UpdateRefreshrate(); + } ++#elif defined(TARGET_RASPBERRY_PI) ++bool CVideoReferenceClock::SetupOMX() +{ -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); ++ CLog::Log(LOGDEBUG, "CVideoReferenceClock: setting up OMX"); + -+ m_Initialized = false; -+ m_last_src_fmt = AV_SAMPLE_FMT_NONE; -+ m_last_dst_fmt = AV_SAMPLE_FMT_NONE; -+ m_last_src_channels = 0; -+ m_last_dst_channels = 0; -+} -+ -+CActiveAEResample::~CActiveAEResample() -+{ -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -+ DeInit(); -+} -+ -+void CActiveAEResample::DeInit() -+{ -+ CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__); -+ if (m_Initialized) -+ { -+ m_omx_mixer.FlushAll(); -+ m_omx_mixer.Deinitialize(); -+ m_Initialized = false; -+ } -+} -+ -+bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality) -+{ -+ LOGTIMEINIT("x"); -+ -+ CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d rate:%d->%d format:%d->%d bits:%d->%d norm:%d upmix:%d", CLASSNAME, __func__, remapLayout, src_channels, dst_channels, src_rate, dst_rate, src_fmt, dst_fmt, src_bits, dst_bits, normalize, upmix); -+ -+ if (src_bits == 0) -+ { -+ if (src_fmt == AV_SAMPLE_FMT_U8) src_bits = 8; -+ else if (src_fmt == AV_SAMPLE_FMT_S16) src_bits = 16; -+ else if (src_fmt == AV_SAMPLE_FMT_S32) src_bits = 32; -+ else if (src_fmt == AV_SAMPLE_FMT_FLT) src_bits = 32; -+ } -+ assert(src_bits && dst_bits); -+ -+ m_dst_chan_layout = dst_chan_layout; -+ m_dst_channels = dst_channels; -+ m_dst_rate = dst_rate; -+ m_dst_fmt = dst_fmt; -+ m_dst_bits = dst_bits; -+ m_src_chan_layout = src_chan_layout; -+ m_src_channels = src_channels; -+ m_src_rate = src_rate; -+ m_src_fmt = src_fmt; -+ m_src_bits = src_bits; -+ -+ if (m_dst_chan_layout == 0) -+ m_dst_chan_layout = av_get_default_channel_layout(m_dst_channels); -+ if (m_src_chan_layout == 0) -+ m_src_chan_layout = av_get_default_channel_layout(m_src_channels); -+ -+ OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix; -+ OMX_INIT_STRUCTURE(mix); -+ -+ assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64); -+ -+ LOGTIME(1); -+// this code is just uses ffmpeg to produce the 8x8 mixing matrix -+{ -+ // dummy sample rate and format, as we only care about channel mapping -+ SwrContext *m_pContext = swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000, -+ m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL); -+ if (!m_pContext) -+ { -+ CLog::Log(LOGERROR, "CActiveAEResample::Init - create context failed"); -+ return false; -+ } -+ // tell resampler to clamp float values -+ // not required for sink stage (remapLayout == true) -+ if (!remapLayout && normalize) -+ { -+ av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0); -+ } -+ -+ if (remapLayout) -+ { -+ // one-to-one mapping of channels -+ // remapLayout is the layout of the sink, if the channel is in our src layout -+ // the channel is mapped by setting coef 1.0 -+ double m_rematrix[AE_CH_MAX][AE_CH_MAX]; -+ memset(m_rematrix, 0, sizeof(m_rematrix)); -+ m_dst_chan_layout = 0; -+ for (unsigned int out=0; outCount(); out++) -+ { -+ m_dst_chan_layout += (uint64_t) (1 << out); -+ int idx = GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout); -+ if (idx >= 0) -+ { -+ m_rematrix[out][idx] = 1.0; -+ } -+ } -+ -+ av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0); -+ av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0); -+ -+ if (swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0) -+ { -+ CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed"); -+ return false; -+ } -+ } -+ // stereo upmix -+ else if (upmix && m_src_channels == 2 && m_dst_channels > 2) -+ { -+ double m_rematrix[AE_CH_MAX][AE_CH_MAX]; -+ memset(m_rematrix, 0, sizeof(m_rematrix)); -+ for (int out=0; out%d (%.2f)", CLASSNAME, __func__, src_samples, dst_samples, ratio); -+ #endif -+ if (!m_Initialized) -+ return 0; -+ OMX_ERRORTYPE omx_err = OMX_ErrorNone; ++ CSingleLock SingleLock(m_CritSection); ++ SingleLock.Leave(); + -+ const int s_pitch = m_pcm_input.nChannels * m_src_bits >> 3; -+ const int d_pitch = m_pcm_output.nChannels * m_dst_bits >> 3; -+ int sent = 0; -+ int received = 0; -+ while (sent < src_samples) ++ while(!m_bStop) + { -+ OMX_BUFFERHEADERTYPE *omx_buffer = NULL; -+ OMX_BUFFERHEADERTYPE *m_encoded_buffer = NULL; ++ g_RBP.WaitVsync(); + -+ omx_buffer = m_omx_mixer.GetInputBuffer(1000); -+ if (omx_buffer == NULL) -+ return false; ++ m_RefreshRate = g_graphicsContext.GetFPS(); ++ CLog::Log(LOGDEBUG, "CVideoReferenceClock:%s fps:%.2f missed:%d Time:%.3f", __func__, m_RefreshRate, m_TotalMissedVblanks, m_CurrTime * 1e-6); ++ //update the vblank timestamp, update the clock and send a signal that we got a vblank ++ SingleLock.Enter(); ++ m_VblankTime = CurrentHostCounter(); ++ UpdateClock(1, true); ++ SingleLock.Leave(); ++ SendVblankSignal(); + -+ const int max_src_samples = BUFFERSIZE / s_pitch; -+ const int max_dst_samples = (long long)(BUFFERSIZE/d_pitch) * m_src_rate / (m_dst_rate + m_src_rate-1); -+ int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent); -+ -+ omx_buffer->nOffset = 0; -+ omx_buffer->nFlags = OMX_BUFFERFLAG_EOS; -+ omx_buffer->nFilledLen = send * s_pitch; -+ -+ assert(omx_buffer->nFilledLen > 0 && omx_buffer->nFilledLen <= omx_buffer->nAllocLen); -+ -+ if (omx_buffer->nFilledLen) ++ if (UpdateRefreshrate()) + { -+ memcpy(omx_buffer->pBuffer, src_buffer[0] + sent * s_pitch, omx_buffer->nFilledLen); -+ sent += send; ++ //we have to measure the refreshrate again ++ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Displaymode changed"); ++ return; + } -+ -+ omx_err = m_omx_mixer.EmptyThisBuffer(omx_buffer); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ -+ m_encoded_buffer = m_omx_mixer.GetOutputBuffer(); -+ -+ if (!m_encoded_buffer) -+ { -+ CLog::Log(LOGERROR, "%s::%s no output buffer", CLASSNAME, __func__); -+ return false; -+ } -+ -+ omx_err = m_omx_mixer.FillThisBuffer(m_encoded_buffer); -+ if (omx_err != OMX_ErrorNone) -+ return false; -+ -+ omx_err = m_omx_mixer.WaitForOutputDone(1000); -+ if (omx_err != OMX_ErrorNone) -+ { -+ CLog::Log(LOGERROR, "%s::%s m_omx_mixer.WaitForOutputDone result(0x%x)", CLASSNAME, __func__, omx_err); -+ return false; -+ } -+ assert(m_encoded_buffer->nFilledLen > 0 && m_encoded_buffer->nFilledLen <= m_encoded_buffer->nAllocLen); -+ -+ if (m_omx_mixer.BadState()) -+ { -+ CLog::Log(LOGERROR, "%s::%s m_omx_mixer.BadState", CLASSNAME, __func__); -+ return false; -+ } -+ -+ if (m_encoded_buffer->nFilledLen) -+ { -+ memcpy(dst_buffer[0] + received * d_pitch, m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen); -+ received += m_encoded_buffer->nFilledLen / d_pitch; -+ } -+ } -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s format:%d->%d rate:%d->%d chan:%d->%d samples %d->%d (%f) %d =%d", CLASSNAME, __func__, -+ (int)m_src_fmt, (int)m_dst_fmt, m_src_rate, m_dst_rate, m_src_channels, m_dst_channels, src_samples, dst_samples, ratio, m_Initialized, received); -+ #endif -+ return received; -+} -+ -+int64_t CActiveAEResample::GetDelay(int64_t base) -+{ -+ int ret = 0; -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); -+ #endif -+ return ret; -+} -+ -+int CActiveAEResample::GetBufferedSamples() -+{ -+ int ret = 0; -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); -+ #endif -+ return ret; -+} -+ -+int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate) -+{ -+ int ret = ((long long)src_samples * dst_rate + src_rate-1) / src_rate; -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); -+ #endif -+ return ret; -+} -+ -+int CActiveAEResample::GetSrcBufferSize(int samples) -+{ -+ int ret = 0; -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); -+ #endif -+ return ret; -+} -+ -+int CActiveAEResample::GetDstBufferSize(int samples) -+{ -+ int ret = CalcDstSampleCount(samples, m_dst_rate, m_src_rate); -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); -+ #endif -+ return ret; -+} -+ -+uint64_t CActiveAEResample::GetAVChannelLayout(CAEChannelInfo &info) -+{ -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -+ #endif -+ uint64_t channelLayout = 0; -+ if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT; -+ if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT; -+ if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER; -+ if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY; -+ if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT; -+ if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT; -+ if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER; -+ if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER; -+ if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER; -+ if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT; -+ if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT; -+ if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER; -+ if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT; -+ if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER; -+ if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT; -+ if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT; -+ if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER; -+ if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT; -+ -+ return channelLayout; -+} -+ -+AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) -+{ -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -+ #endif -+ if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8; -+ else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; -+ else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; -+ else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32; -+ else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; -+ else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; -+ -+ else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P; -+ else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; -+ else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; -+ else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P; -+ else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; -+ else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; -+ -+ if (AE_IS_PLANAR(format)) -+ return AV_SAMPLE_FMT_FLTP; -+ else -+ return AV_SAMPLE_FMT_FLT; -+} -+ -+AEDataFormat CActiveAEResample::GetAESampleFormat(AVSampleFormat format, int bits) -+{ -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -+ #endif -+ if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8; -+ else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE; -+ else if (format == AV_SAMPLE_FMT_S32 && bits == 32) return AE_FMT_S32NE; -+ else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4; -+ else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT; -+ else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE; -+ -+ else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P; -+ else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP; -+ else if (format == AV_SAMPLE_FMT_S32P && bits == 32) return AE_FMT_S32NEP; -+ else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4P; -+ else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP; -+ else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP; -+ -+ CLog::Log(LOGERROR, "CActiveAEResample::GetAESampleFormat - format not supported"); -+ return AE_FMT_INVALID; -+} -+ -+uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel) -+{ -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -+ #endif -+ switch (aechannel) -+ { -+ case AE_CH_FL: return AV_CH_FRONT_LEFT; -+ case AE_CH_FR: return AV_CH_FRONT_RIGHT; -+ case AE_CH_FC: return AV_CH_FRONT_CENTER; -+ case AE_CH_LFE: return AV_CH_LOW_FREQUENCY; -+ case AE_CH_BL: return AV_CH_BACK_LEFT; -+ case AE_CH_BR: return AV_CH_BACK_RIGHT; -+ case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER; -+ case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER; -+ case AE_CH_BC: return AV_CH_BACK_CENTER; -+ case AE_CH_SL: return AV_CH_SIDE_LEFT; -+ case AE_CH_SR: return AV_CH_SIDE_RIGHT; -+ case AE_CH_TC: return AV_CH_TOP_CENTER; -+ case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT; -+ case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER; -+ case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT; -+ case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT; -+ case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER; -+ case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT; -+ default: -+ return 0; + } +} + -+int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) ++void CVideoReferenceClock::CleanupOMX() +{ -+ #ifdef DEBUG_VERBOSE -+ CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -+ #endif -+ return av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); ++ CLog::Log(LOGDEBUG, "CVideoReferenceClock: cleaning up OMX"); +} -+ -+#endif -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h -new file mode 100644 -index 0000000..47a9e08 ---- /dev/null -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h -@@ -0,0 +1,62 @@ -+#pragma once -+/* -+ * Copyright (C) 2010-2013 Team XBMC -+ * http://xbmc.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, 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 XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "linux/OMXCore.h" -+ -+namespace ActiveAE -+{ -+ -+class CActiveAEResample -+{ -+public: -+ CActiveAEResample(); -+ virtual ~CActiveAEResample(); -+ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality); -+ int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio); -+ int64_t GetDelay(int64_t base); -+ int GetBufferedSamples(); -+ int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate); -+ int GetSrcBufferSize(int samples); -+ int GetDstBufferSize(int samples); -+ static uint64_t GetAVChannelLayout(CAEChannelInfo &info); -+// static CAEChannelInfo GetAEChannelLayout(uint64_t layout); -+ static AVSampleFormat GetAVSampleFormat(AEDataFormat format); -+ static AEDataFormat GetAESampleFormat(AVSampleFormat format, int bits); -+ static uint64_t GetAVChannel(enum AEChannel aechannel); -+ int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); -+ -+protected: -+ void DeInit(); -+ uint64_t m_src_chan_layout, m_dst_chan_layout; -+ int m_src_rate, m_dst_rate; -+ int m_src_channels, m_dst_channels; -+ AVSampleFormat m_src_fmt, m_dst_fmt; -+ int m_src_bits, m_dst_bits; -+ -+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input; -+ OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output; -+ COMXCoreComponent m_omx_mixer; -+ bool m_Initialized; -+ AVSampleFormat m_last_src_fmt, m_last_dst_fmt; -+ int m_last_src_channels, m_last_dst_channels; -+}; -+ -+} -diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in -index 581249e..20c05bb 100644 ---- a/xbmc/cores/AudioEngine/Makefile.in -+++ b/xbmc/cores/AudioEngine/Makefile.in -@@ -31,6 +31,7 @@ SRCS += Engines/ActiveAE/ActiveAESink.cpp - SRCS += Engines/ActiveAE/ActiveAEStream.cpp - SRCS += Engines/ActiveAE/ActiveAESound.cpp - SRCS += Engines/ActiveAE/ActiveAEResample.cpp -+SRCS += Engines/ActiveAE/ActiveAEResamplePi.cpp - SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp + #endif - ifeq (@USE_ANDROID@,1) -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp -index 5a45653..2733054 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp -@@ -78,9 +78,9 @@ static void SetAudioProps(bool stream_channels, uint32_t channel_map) - CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map); - } + //this is called from the vblank run function and from CVideoReferenceClock::Wait in case of a late update +diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h +index 6027031..2dabac1 100644 +--- a/xbmc/video/VideoReferenceClock.h ++++ b/xbmc/video/VideoReferenceClock.h +@@ -150,6 +150,12 @@ class CVideoReferenceClock : public CThread --static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough) -+static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough) - { -- unsigned int channels = format.m_channelLayout.Count(); -+ unsigned int channels = channelLayout.Count(); - uint32_t channel_map = 0; - if (passthrough) - return 0; -@@ -119,12 +119,12 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough) - // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels - // but no BR BL channels, we use the wide map in order to open only the num of channels really - // needed. -- if (format.m_channelLayout.HasChannel(AE_CH_BL) && !format.m_channelLayout.HasChannel(AE_CH_SL)) -+ if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL)) - map = map_back; + int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened + //not the same as m_VblankTime ++#elif defined(TARGET_RASPBERRY_PI) ++ bool SetupOMX(); ++ void RunOMX(); ++ void CleanupOMX(); ++ int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened ++ //not the same as m_VblankTime + #endif + }; - for (unsigned int i = 0; i < channels; ++i) - { -- AEChannel c = format.m_channelLayout[i]; -+ AEChannel c = channelLayout[i]; - unsigned int chan = 0; - if ((unsigned int)c < sizeof map_normal / sizeof *map_normal) - chan = map[(unsigned int)c]; -@@ -155,9 +155,9 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough) - 0xff, // 7 - 0x13, // 7.1 - }; -- uint8_t cea = format.m_channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels]; -+ uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels]; - if (cea == 0xff) -- CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, format.m_channelLayout.HasChannel(AE_CH_LFE), channels); -+ CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels); - - channel_map |= cea << 24; - -@@ -191,7 +191,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device) - format.m_frames = format.m_sampleRate * AUDIO_PLAYBUFFER / NUM_OMX_BUFFERS; - format.m_frameSamples = format.m_frames * channels; - -- SetAudioProps(m_passthrough, GetChannelMap(format, m_passthrough)); -+ SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough)); - - m_format = format; - m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate); -diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp -index 6cc4970..2ac9b7e 100644 ---- a/xbmc/linux/OMXCore.cpp -+++ b/xbmc/linux/OMXCore.cpp -@@ -419,7 +419,7 @@ void COMXCoreComponent::FlushAll() - - void COMXCoreComponent::FlushInput() - { -- if(!m_handle) -+ if(!m_handle || m_resource_error) - return; - - OMX_ERRORTYPE omx_err = OMX_ErrorNone; -@@ -441,7 +441,7 @@ void COMXCoreComponent::FlushInput() - - void COMXCoreComponent::FlushOutput() - { -- if(!m_handle) -+ if(!m_handle || m_resource_error) - return; - - OMX_ERRORTYPE omx_err = OMX_ErrorNone; --- -2.0.4 - -From 73e940d99eb8f4ca6c0c604effb3c93c6636f430 Mon Sep 17 00:00:00 2001 +From 368010b61ed9b84fd9ad667cbae70f1f418ca016 Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Sun, 1 Jun 2014 12:15:17 +0100 -Subject: [PATCH 63/98] [resamplepi] Support planar formats +Date: Tue, 12 Aug 2014 00:03:18 +0100 +Subject: [PATCH 35/77] videoreferenceclock: Boost priority --- - .../Engines/ActiveAE/ActiveAEResamplePi.cpp | 101 ++++++++++++--------- - 1 file changed, 59 insertions(+), 42 deletions(-) + xbmc/video/VideoReferenceClock.cpp | 3 +++ + 1 file changed, 3 insertions(+) -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -index 9a1e549..1604030 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -@@ -88,20 +88,36 @@ void CActiveAEResample::DeInit() - } - } +diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp +index 916a15c..c491d29 100644 +--- a/xbmc/video/VideoReferenceClock.cpp ++++ b/xbmc/video/VideoReferenceClock.cpp +@@ -157,6 +157,9 @@ void CVideoReferenceClock::Process() + bool SetupSuccess = false; + int64_t Now; -+static int format_to_bits(AVSampleFormat fmt) -+{ -+ switch (fmt) -+ { -+ case AV_SAMPLE_FMT_U8: -+ case AV_SAMPLE_FMT_U8P: -+ return 8; -+ case AV_SAMPLE_FMT_S16: -+ case AV_SAMPLE_FMT_S16P: -+ return 16; -+ case AV_SAMPLE_FMT_S32: -+ case AV_SAMPLE_FMT_S32P: -+ case AV_SAMPLE_FMT_FLT: -+ case AV_SAMPLE_FMT_FLTP: -+ return 32; -+ default: -+ assert(0); -+ } -+ return 0; -+} ++ /* This shouldn't be very busy and timing is important so increase priority */ ++ SetPriority(GetPriority()+1); + - bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, int dst_dither, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, int src_dither, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality) - { - LOGTIMEINIT("x"); + #if defined(TARGET_WINDOWS) && defined(HAS_DX) + //register callback + m_D3dCallback.Reset(); + +From 28cd39d1b3695fdd464e7a5b200817115be4e5b1 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 5 Feb 2014 11:46:33 +0000 +Subject: [PATCH 36/77] [rbp/settings] Allow av sync type to be enabled + +It works for dvdplayer +--- + system/settings/rbp.xml | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml +index 28e68eb..60086d8 100644 +--- a/system/settings/rbp.xml ++++ b/system/settings/rbp.xml +@@ -1,13 +1,6 @@ + + +
+- +- +- +- false +- +- +- + + + false + + +From 162a1d6ee9b5603e6df798289d6843380e3a5cf0 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 16 Apr 2014 21:18:06 +0100 +Subject: [PATCH 41/77] [omxplayer] Don't propagate 3d flags based on supported + 3d modes + +--- + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++------------------------- + 1 file changed, 4 insertions(+), 25 deletions(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index 2c25fd9..c2bd788 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -759,36 +759,15 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f + unsigned flags = 0; + ERenderFormat format = RENDER_FMT_BYPASS; - CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d rate:%d->%d format:%d->%d bits:%d->%d norm:%d upmix:%d", CLASSNAME, __func__, remapLayout, src_channels, dst_channels, src_rate, dst_rate, src_fmt, dst_fmt, src_bits, dst_bits, normalize, upmix); - -- if (src_bits == 0) ++ /* figure out steremode expected based on user settings and hints */ ++ unsigned int stereo_flags = GetStereoModeFlags(GetStereoMode()); ++ + if(m_bAllowFullscreen) + { + flags |= CONF_FLAGS_FULLSCREEN; + m_bAllowFullscreen = false; // only allow on first configure + } +- +- flags |= GetStereoModeFlags(GetStereoMode()); +- +- if(flags & CONF_FLAGS_STEREO_MODE_SBS) - { -- if (src_fmt == AV_SAMPLE_FMT_U8) src_bits = 8; -- else if (src_fmt == AV_SAMPLE_FMT_S16) src_bits = 16; -- else if (src_fmt == AV_SAMPLE_FMT_S32) src_bits = 32; -- else if (src_fmt == AV_SAMPLE_FMT_FLT) src_bits = 32; +- if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS)) +- CLog::Log(LOGNOTICE, "3DSBS movie found"); +- else +- { +- flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0); +- CLog::Log(LOGNOTICE, "3DSBS movie found but not supported"); +- } - } -- assert(src_bits && dst_bits); -+ // replace passed in number of bits with correct ones -+ src_bits = format_to_bits(src_fmt); -+ dst_bits = format_to_bits(dst_fmt); +- else if(flags & CONF_FLAGS_STEREO_MODE_TAB) +- { +- if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB)) +- CLog::Log(LOGNOTICE, "3DTB movie found"); +- else +- { +- flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0); +- CLog::Log(LOGNOTICE, "3DTB movie found but not supported"); +- } +- } +- else +- CLog::Log(LOGNOTICE, "not a 3D movie"); ++ flags |= stereo_flags; - m_dst_chan_layout = dst_chan_layout; - m_dst_channels = dst_channels; -@@ -139,7 +155,7 @@ bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst - // not required for sink stage (remapLayout == true) - if (!remapLayout && normalize) + unsigned int iDisplayWidth = width; + unsigned int iDisplayHeight = height; + +From b4b030a3c528926f1a66c22e4a03a5a69aac5f94 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 17 Apr 2014 13:00:52 +0100 +Subject: [PATCH 42/77] [graphics] Don't set stereo mode based on resolution + +The resolution change should follow stereo mode +--- + xbmc/guilib/GraphicContext.cpp | 35 +++++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp +index 5bffdf5..4be1c8b 100644 +--- a/xbmc/guilib/GraphicContext.cpp ++++ b/xbmc/guilib/GraphicContext.cpp +@@ -420,26 +420,29 @@ void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate) + RESOLUTION_INFO info_org = CDisplaySettings::Get().GetResolutionInfo(res); + RESOLUTION_INFO info_last = CDisplaySettings::Get().GetResolutionInfo(lastRes); + +- RENDER_STEREO_MODE stereo_mode = m_stereoMode; +- + // if the new mode is an actual stereo mode, switch to that + // if the old mode was an actual stereo mode, switch to no 3d mode +- if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB) +- stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; +- else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS) +- stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; +- else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0 +- || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB) != 0) +- stereo_mode = RENDER_STEREO_MODE_OFF; +- +- if(stereo_mode != m_stereoMode) ++ // only do this if 3D flags have changed ++ if ((info_org.dwFlags ^ info_last.dwFlags) & (D3DPRESENTFLAG_MODE3DTB | D3DPRESENTFLAG_MODE3DSBS)) { -- av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0); -+ av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0); - } - - if (remapLayout) -@@ -264,7 +280,13 @@ bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst - m_pcm_input.eEndian = OMX_EndianLittle; - m_pcm_input.bInterleaved = OMX_TRUE; - m_pcm_input.nBitPerSample = m_src_bits; -- m_pcm_input.ePCMMode = m_src_fmt == AV_SAMPLE_FMT_FLT ? (OMX_AUDIO_PCMMODETYPE)0x8000 : OMX_AUDIO_PCMModeLinear; -+ // 0x8000 = float, 0x10000 = planar -+ uint32_t flags = 0; -+ if (m_src_fmt == AV_SAMPLE_FMT_FLT || m_src_fmt == AV_SAMPLE_FMT_FLTP) -+ flags |= 0x8000; -+ if (m_src_fmt >= AV_SAMPLE_FMT_U8P) -+ flags |= 0x10000; -+ m_pcm_input.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags; - m_pcm_input.nChannels = src_channels; - m_pcm_input.nSamplingRate = src_rate; - -@@ -278,7 +300,12 @@ bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst - m_pcm_output.eEndian = OMX_EndianLittle; - m_pcm_output.bInterleaved = OMX_TRUE; - m_pcm_output.nBitPerSample = m_dst_bits; -- m_pcm_output.ePCMMode = m_dst_fmt == AV_SAMPLE_FMT_FLT ? (OMX_AUDIO_PCMMODETYPE)0x8000 : OMX_AUDIO_PCMModeLinear; -+ flags = 0; -+ if (m_dst_fmt == AV_SAMPLE_FMT_FLT || m_dst_fmt == AV_SAMPLE_FMT_FLTP) -+ flags |= 0x8000; -+ if (m_dst_fmt >= AV_SAMPLE_FMT_U8P) -+ flags |= 0x10000; -+ m_pcm_output.ePCMMode = flags == 0 ? OMX_AUDIO_PCMModeLinear : (OMX_AUDIO_PCMMODETYPE)flags; - m_pcm_output.nChannels = dst_channels; - m_pcm_output.nSamplingRate = dst_rate; - -@@ -364,8 +391,13 @@ int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t * - return 0; - OMX_ERRORTYPE omx_err = OMX_ErrorNone; - -- const int s_pitch = m_pcm_input.nChannels * m_src_bits >> 3; -- const int d_pitch = m_pcm_output.nChannels * m_dst_bits >> 3; -+ const int s_planes = m_src_fmt >= AV_SAMPLE_FMT_U8P ? m_src_channels : 1; -+ const int d_planes = m_dst_fmt >= AV_SAMPLE_FMT_U8P ? m_dst_channels : 1; -+ const int s_chans = m_src_fmt >= AV_SAMPLE_FMT_U8P ? 1 : m_src_channels; -+ const int d_chans = m_dst_fmt >= AV_SAMPLE_FMT_U8P ? 1 : m_dst_channels; -+ const int s_pitch = s_chans * m_src_bits >> 3; -+ const int d_pitch = d_chans * m_dst_bits >> 3; +- m_stereoView = RENDER_STEREO_VIEW_OFF; +- m_stereoMode = stereo_mode; +- m_nextStereoMode = stereo_mode; +- CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode); +- } ++ RENDER_STEREO_MODE stereo_mode = m_stereoMode; + - int sent = 0; - int received = 0; - while (sent < src_samples) -@@ -377,19 +409,23 @@ int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t * - if (omx_buffer == NULL) - return false; ++ if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB) ++ stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL; ++ else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ++ stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL; ++ else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0 ++ || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB) != 0) ++ stereo_mode = RENDER_STEREO_MODE_OFF; -- const int max_src_samples = BUFFERSIZE / s_pitch; -- const int max_dst_samples = (long long)(BUFFERSIZE/d_pitch) * m_src_rate / (m_dst_rate + m_src_rate-1); -+ const int s_samplesize = m_src_channels * m_src_bits >> 3; -+ const int d_samplesize = m_dst_channels * m_dst_bits >> 3; -+ const int max_src_samples = BUFFERSIZE / s_samplesize; -+ const int max_dst_samples = (long long)(BUFFERSIZE / d_samplesize) * m_src_rate / (m_dst_rate + m_src_rate-1); - int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent); ++ if(stereo_mode != m_stereoMode) ++ { ++ m_stereoView = RENDER_STEREO_VIEW_OFF; ++ m_stereoMode = stereo_mode; ++ m_nextStereoMode = stereo_mode; ++ CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode); ++ } ++ } + RESOLUTION_INFO info_mod = GetResInfo(res); - omx_buffer->nOffset = 0; - omx_buffer->nFlags = OMX_BUFFERFLAG_EOS; -- omx_buffer->nFilledLen = send * s_pitch; -+ omx_buffer->nFilledLen = send * s_samplesize; + m_iScreenWidth = info_mod.iWidth; + +From b0d51a841696f2a2ecc303ef5bd233f21d6d0f42 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 17 Apr 2014 13:01:51 +0100 +Subject: [PATCH 43/77] [graphics] Allow switching to a more suitable 3D + resolution + +--- + xbmc/guilib/GraphicContext.cpp | 40 +++++++++++++++++++++++++++++++++++++++- + xbmc/guilib/GraphicContext.h | 1 + + 2 files changed, 40 insertions(+), 1 deletion(-) + +diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp +index 4be1c8b..792a77d 100644 +--- a/xbmc/guilib/GraphicContext.cpp ++++ b/xbmc/guilib/GraphicContext.cpp +@@ -35,6 +35,7 @@ + #include "utils/JobManager.h" + #include "video/VideoReferenceClock.h" + #include "cores/IPlayer.h" ++#include - assert(omx_buffer->nFilledLen > 0 && omx_buffer->nFilledLen <= omx_buffer->nAllocLen); + using namespace std; - if (omx_buffer->nFilledLen) - { -- memcpy(omx_buffer->pBuffer, src_buffer[0] + sent * s_pitch, omx_buffer->nFilledLen); -+ int planesize = omx_buffer->nFilledLen / s_planes; -+ for (int i=0; i < s_planes; i++) -+ memcpy((uint8_t *)omx_buffer->pBuffer + i * planesize, src_buffer[i] + sent * s_pitch, planesize); - sent += send; - } - -@@ -428,8 +464,10 @@ int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t * - - if (m_encoded_buffer->nFilledLen) - { -- memcpy(dst_buffer[0] + received * d_pitch, m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen); -- received += m_encoded_buffer->nFilledLen / d_pitch; -+ int planesize = m_encoded_buffer->nFilledLen / d_planes; -+ for (int i=0; i < d_planes; i++) -+ memcpy(dst_buffer[i] + received * d_pitch, (uint8_t *)m_encoded_buffer->pBuffer + i * planesize, planesize); -+ received += m_encoded_buffer->nFilledLen / d_samplesize; - } - } - #ifdef DEBUG_VERBOSE -@@ -521,6 +559,7 @@ AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) - else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; - else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; - else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32; -+ else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32; - else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; - else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; - -@@ -528,6 +567,7 @@ AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) - else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; - else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; - else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P; -+ else if (format == AE_FMT_S24NE4MSB)return AV_SAMPLE_FMT_S32; - else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; - else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; - -@@ -537,29 +577,6 @@ AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) - return AV_SAMPLE_FMT_FLT; +@@ -484,6 +485,43 @@ RESOLUTION CGraphicContext::GetVideoResolution() const + return m_Resolution; } --AEDataFormat CActiveAEResample::GetAESampleFormat(AVSampleFormat format, int bits) --{ -- #ifdef DEBUG_VERBOSE -- CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__); -- #endif -- if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8; -- else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE; -- else if (format == AV_SAMPLE_FMT_S32 && bits == 32) return AE_FMT_S32NE; -- else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4; -- else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT; -- else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE; -- -- else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P; -- else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP; -- else if (format == AV_SAMPLE_FMT_S32P && bits == 32) return AE_FMT_S32NEP; -- else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4P; -- else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP; -- else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP; -- -- CLog::Log(LOGERROR, "CActiveAEResample::GetAESampleFormat - format not supported"); -- return AE_FMT_INVALID; --} -- - uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel) ++RESOLUTION CGraphicContext::Get3DVideoResolution(RESOLUTION resolution, RENDER_STEREO_MODE mode) const ++{ ++ RESOLUTION best = resolution; ++ RESOLUTION_INFO curr = CDisplaySettings::Get().GetResolutionInfo(best); ++ // Find closest refresh rate ++ for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) ++ { ++ const RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo((RESOLUTION)i); ++ ++ //discard resolutions that are not the same width and height (and interlaced/3D flags) ++ //or have a too low refreshrate ++ if (info.iScreenWidth != curr.iScreenWidth ++ || info.iScreenHeight != curr.iScreenHeight ++ || info.iScreen != curr.iScreen ++ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED) ++ || fabs(info.fRefreshRate - curr.fRefreshRate) >= FLT_EPSILON) ++ continue; ++ ++ if (mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ++ { ++ best = (RESOLUTION)i; ++ break; ++ } ++ else if (mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && info.dwFlags & D3DPRESENTFLAG_MODE3DTB) ++ { ++ best = (RESOLUTION)i; ++ break; ++ } ++ else if ((mode == RENDER_STEREO_MODE_OFF || mode == RENDER_STEREO_MODE_MONO) && !(info.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB))) ++ { ++ best = (RESOLUTION)i; ++ break; ++ } ++ } ++ return best; ++} ++ + void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res) { - #ifdef DEBUG_VERBOSE --- -2.0.4 - - -From eb889c49af0f988db7f174f18c5b4df9066cb380 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 15 Jun 2014 13:20:53 +0100 -Subject: [PATCH 64/98] gles: Avoid crash when capturing snapshot when using - dvdplayer - -Note: snapshot will be blank, but that's better than crashing ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 2929a37..53873f6 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -1598,7 +1598,9 @@ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture) - return false; - - // If rendered directly by the hardware -+#ifndef TARGET_RASPBERRY_PI - if (m_renderMethod & RENDER_BYPASS) -+#endif + res.Overscan.left = 0; +@@ -1021,7 +1059,7 @@ void CGraphicContext::Flip(const CDirtyRegionList& dirty) + if(m_stereoMode != m_nextStereoMode) { - capture->BeginRender(); - capture->EndRender(); --- -2.0.4 + m_stereoMode = m_nextStereoMode; +- SetVideoResolution(GetVideoResolution(), true); ++ SetVideoResolution(Get3DVideoResolution(m_Resolution, m_stereoMode), true); + g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET); + } + } +diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h +index 0a27643..ef5bc74 100644 +--- a/xbmc/guilib/GraphicContext.h ++++ b/xbmc/guilib/GraphicContext.h +@@ -108,6 +108,7 @@ class CGraphicContext : public CCriticalSection, + bool IsValidResolution(RESOLUTION res); + void SetVideoResolution(RESOLUTION res, bool forceUpdate = false); + RESOLUTION GetVideoResolution() const; ++ RESOLUTION Get3DVideoResolution(RESOLUTION resolution, RENDER_STEREO_MODE mode) const; + void ResetOverscan(RESOLUTION res, OVERSCAN &overscan); + void ResetOverscan(RESOLUTION_INFO &resinfo); + void ResetScreenParameters(RESOLUTION res); + +From 7278fb51a95d2f6d07cd4bca238d0a148887c5c3 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Thu, 17 Apr 2014 13:38:55 +0100 +Subject: [PATCH 44/77] [3D] Support switching to 3D resolutions + +Include matching 3D flags (SBS/TAB) in the score of a resolution to switch to, to enable switching to 3d modes. +Also remove the old code that treated 3D modes differently when assigning a score. +--- + xbmc/cores/VideoRenderers/BaseRenderer.cpp | 47 +++++++++++------------------- + 1 file changed, 17 insertions(+), 30 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp +index 83c3adb..8076e76 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp +@@ -222,10 +222,14 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight) + RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight) + { + RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current); ++ RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode(); + + float fRefreshRate = fps; + +- float last_diff = fRefreshRate; ++ int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0); ++ if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) || ++ !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DTB)) ++ c_weight += 1000; + + // Find closest refresh rate + for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) +@@ -241,40 +245,23 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES + || info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001) + continue; + +- // For 3D choose the closest refresh rate +- if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags)) +- { +- float diff = (info.fRefreshRate - fRefreshRate); +- if(diff < 0) +- diff *= -1.0f; ++ int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0); + +- if(diff < last_diff) +- { +- last_diff = diff; +- current = (RESOLUTION)i; +- curr = info; +- } +- } +- else +- { +- int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0); +- int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0); ++ if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) || ++ !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)) ++ i_weight += 1000; + +- // Closer the better, prefer higher refresh rate if the same +- if ((i_weight < c_weight) +- || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate)) +- { +- current = (RESOLUTION)i; +- curr = info; +- } ++ // Closer the better, prefer higher refresh rate if the same ++ if ((i_weight < c_weight) ++ || (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate)) ++ { ++ current = (RESOLUTION)i; ++ curr = info; ++ c_weight = i_weight; + } + } + +- // For 3D overwrite weight +- if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags)) +- weight = 0; +- else +- weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier); ++ weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier); + + return current; + } + +From d9820ca27cef34a9dc0025487290e36768f0fbd4 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 23 Apr 2014 00:05:07 +0100 +Subject: [PATCH 45/77] [graphics] Make pixel ratio for 3d modes consistent + +Note: Use the stored stereo flags from lists of resolutions. +Use current stereo mode for current resolution. +--- + xbmc/cores/VideoRenderers/BaseRenderer.cpp | 10 +++---- + xbmc/guilib/GraphicContext.cpp | 37 ++++++++++++------------- + xbmc/guilib/GraphicContext.h | 12 ++++++-- + xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 8 ------ + 4 files changed, 32 insertions(+), 35 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp +index 8076e76..9118cb0 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp +@@ -119,7 +119,7 @@ bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fa + + for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::Get().ResolutionInfoSize(); j++) + { +- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j); ++ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j, g_graphicsContext.GetStereoMode((RESOLUTION)j)); + + if (info.iScreenWidth == curr.iScreenWidth + && info.iScreenHeight == curr.iScreenHeight +@@ -179,7 +179,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight) + //get the resolution with the refreshrate closest to 60 hertz + for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) + { +- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); ++ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, g_graphicsContext.GetStereoMode((RESOLUTION)i)); + + if (MathUtils::round_int(info.fRefreshRate) == 60 + && info.iScreenWidth == curr.iScreenWidth +@@ -200,7 +200,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight) + CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest"); + for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) + { +- RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); ++ RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, g_graphicsContext.GetStereoMode((RESOLUTION)i)); + + if (info.fRefreshRate > curr.fRefreshRate + && info.iScreenWidth == curr.iScreenWidth +@@ -234,14 +234,14 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES + // Find closest refresh rate + for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++) + { +- const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i); ++ const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, g_graphicsContext.GetStereoMode((RESOLUTION)i)); + + //discard resolutions that are not the same width and height (and interlaced/3D flags) + //or have a too low refreshrate + if (info.iScreenWidth != curr.iScreenWidth + || info.iScreenHeight != curr.iScreenHeight + || info.iScreen != curr.iScreen +- || (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK) ++ || (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED) + || info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001) + continue; + +diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp +index 792a77d..4890711 100644 +--- a/xbmc/guilib/GraphicContext.cpp ++++ b/xbmc/guilib/GraphicContext.cpp +@@ -731,32 +731,33 @@ void CGraphicContext::ApplyStateBlock() + g_Windowing.ApplyStateBlock(); + } + +-const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const ++RENDER_STEREO_MODE CGraphicContext::GetStereoMode(RESOLUTION res) const + { + RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res); ++ return (info.dwFlags & D3DPRESENTFLAG_MODE3DTB) ? RENDER_STEREO_MODE_SPLIT_HORIZONTAL : ++ (info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ? RENDER_STEREO_MODE_SPLIT_VERTICAL : RENDER_STEREO_MODE_OFF; ++} + +- if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) ++const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res, RENDER_STEREO_MODE stereoMode) const ++{ ++ RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res); ++ ++ if(stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) + { +- if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0) +- { +- info.fPixelRatio /= 2; +- info.iBlanking = 0; +- info.dwFlags |= D3DPRESENTFLAG_MODE3DTB; +- } ++ info.fPixelRatio /= 2; ++ info.iBlanking = 0; ++ info.dwFlags |= D3DPRESENTFLAG_MODE3DTB; + info.iHeight = (info.iHeight - info.iBlanking) / 2; + info.Overscan.top /= 2; + info.Overscan.bottom = (info.Overscan.bottom - info.iBlanking) / 2; + info.iSubtitles = (info.iSubtitles - info.iBlanking) / 2; + } + +- if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL) ++ if(stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL) + { +- if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0) +- { +- info.fPixelRatio *= 2; +- info.iBlanking = 0; +- info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; +- } ++ info.fPixelRatio *= 2; ++ info.iBlanking = 0; ++ info.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; + info.iWidth = (info.iWidth - info.iBlanking) / 2; + info.Overscan.left /= 2; + info.Overscan.right = (info.Overscan.right - info.iBlanking) / 2; +@@ -774,16 +775,14 @@ void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info) + if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) + { + curr.Overscan.right = info.Overscan.right * 2 + info.iBlanking; +- if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0) +- curr.fPixelRatio /= 2.0; ++ curr.fPixelRatio /= 2.0; + } + + if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB) + { + curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking; + curr.iSubtitles = info.iSubtitles * 2 + info.iBlanking; +- if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0) +- curr.fPixelRatio *= 2.0; ++ curr.fPixelRatio *= 2.0; + } + } + +diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h +index ef5bc74..c665031 100644 +--- a/xbmc/guilib/GraphicContext.h ++++ b/xbmc/guilib/GraphicContext.h +@@ -120,11 +120,15 @@ class CGraphicContext : public CCriticalSection, + void GetAllowedResolutions(std::vector &res); + + // output scaling ++ const RESOLUTION_INFO GetResInfo(RESOLUTION res) const ++ { ++ return GetResInfo(res, GetStereoMode()); ++ } + const RESOLUTION_INFO GetResInfo() const + { + return GetResInfo(m_Resolution); + } +- const RESOLUTION_INFO GetResInfo(RESOLUTION res) const; ++ const RESOLUTION_INFO GetResInfo(RESOLUTION res, RENDER_STEREO_MODE stereo_mode) const; + void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info); + + /* \brief Get UI scaling information from a given resolution to the screen resolution. +@@ -161,9 +165,11 @@ class CGraphicContext : public CCriticalSection, + void RestoreOrigin(); + void SetCameraPosition(const CPoint &camera); + void SetStereoView(RENDER_STEREO_VIEW view); +- RENDER_STEREO_VIEW GetStereoView() { return m_stereoView; } ++ RENDER_STEREO_VIEW GetStereoView() const { return m_stereoView; } + void SetStereoMode(RENDER_STEREO_MODE mode) { m_nextStereoMode = mode; } +- RENDER_STEREO_MODE GetStereoMode() { return m_stereoMode; } ++ RENDER_STEREO_MODE GetStereoMode() const { return m_stereoMode; } ++ RENDER_STEREO_MODE GetStereoMode(RESOLUTION res) const; ++ + void RestoreCameraPosition(); + /*! \brief Set a region in which to clip all rendering + Anything that is rendered after setting a clip region will be clipped so that no part renders +diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +index c58c28a..bf1e589 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +@@ -449,15 +449,9 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector &r + m_desktopRes.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight); + // Also add 3D flags + if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF) +- { + m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; +- m_desktopRes.fPixelRatio *= 2.0; +- } + else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF) +- { + m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB; +- m_desktopRes.fPixelRatio *= 0.5; +- } + HDMI_PROPERTY_PARAM_T property; + property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE; + vc_tv_hdmi_get_property(&property); +@@ -600,7 +594,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v + RESOLUTION_INFO res2 = res; + res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS; + res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight); +- res2.fPixelRatio *= 2.0f; + res2.iSubtitles = (int)(0.965 * res2.iHeight); + + AddUniqueResolution(res2, resolutions); +@@ -616,7 +609,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v + RESOLUTION_INFO res2 = res; + res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB; + res2.fPixelRatio = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight); +- res2.fPixelRatio *= 0.5f; + res2.iSubtitles = (int)(0.965 * res2.iHeight); + + AddUniqueResolution(res2, resolutions); + +From 19cb0dcb9e872daf649154166104d0ee6c857e75 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sun, 10 Aug 2014 16:45:16 +0100 +Subject: [PATCH 46/77] filesystem: Make support of browsing into archives + optional + +The ability to browse, scan and play content in archives can cause problems on low powered/low memory devices. +It's quite common to see reports of a large rar file that causes xbmc to crash with an out-of-memory error when browsing or scanning. +It also can be slow as any archive in the directory is opened and extracted. + +Add a settings option to enable this feature and default to disabled on Pi +--- + language/English/strings.po | 10 ++++++++++ + system/settings/rbp.xml | 10 ++++++++++ + system/settings/settings.xml | 5 +++++ + xbmc/filesystem/FileDirectoryFactory.cpp | 4 ++++ + 4 files changed, 29 insertions(+) + +diff --git a/language/English/strings.po b/language/English/strings.po +index ade855e..325ed2d 100755 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -15874,3 +15874,13 @@ msgstr "" + msgctxt "#37030" + msgid "Unlimited" + msgstr "" ++ ++#: system/settings/settings.xml ++msgctxt "#37031" ++msgid "Support browsing into archives" ++msgstr "" ++ ++#: system/settings/settings.xml ++msgctxt "#37032" ++msgid "Allow viewing and playing files in archives (e.g. zip, rar)" ++msgstr "" +diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml +index 60086d8..b65136a 100644 +--- a/system/settings/rbp.xml ++++ b/system/settings/rbp.xml +@@ -1,5 +1,15 @@ + + ++
++ ++ ++ ++ false ++ ++ ++ ++
++ +
+ + +diff --git a/system/settings/settings.xml b/system/settings/settings.xml +index af05fb7..f87373a 100644 +--- a/system/settings/settings.xml ++++ b/system/settings/settings.xml +@@ -226,6 +226,11 @@ + false + + ++ ++ 1 ++ true ++ ++ + + + +diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp +index 2fd8777..3b294cd 100644 +--- a/xbmc/filesystem/FileDirectoryFactory.cpp ++++ b/xbmc/filesystem/FileDirectoryFactory.cpp +@@ -46,6 +46,7 @@ + #include "Directory.h" + #include "File.h" + #include "ZipManager.h" ++#include "settings/Settings.h" + #include "settings/AdvancedSettings.h" + #include "FileItem.h" + #include "utils/StringUtils.h" +@@ -142,6 +143,8 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, + return NULL; + } + #endif ++ if (CSettings::Get().GetBool("filelists.browsearchives")) ++ { + if (url.IsFileType("zip")) + { + CURL zipURL = URIUtils::CreateArchivePath("zip", url); +@@ -215,6 +218,7 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, + } + return NULL; + } ++ } + if (url.IsFileType("xsp")) + { // XBMC Smart playlist - just XML renamed to XSP + // read the name of the playlist in -From f4d8961a71c00b39e1e7fdf23c2fe3c56adf2a92 Mon Sep 17 00:00:00 2001 +From 860ade05ad1104e01a1266cd5cf0231e9332fc4a Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 11 Aug 2014 22:56:13 +0100 +Subject: [PATCH 48/77] [omxplayer] Add acceleration option to choose + omxplayer/dvdplayer automatically + +--- + language/English/strings.po | 10 +++++++ + system/settings/settings.xml | 9 ++++++ + xbmc/cores/dvdplayer/DVDPlayer.cpp | 58 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 77 insertions(+) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 325ed2d..1b13a9b 100755 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -15884,3 +15884,13 @@ msgstr "" + msgctxt "#37032" + msgid "Allow viewing and playing files in archives (e.g. zip, rar)" + msgstr "" ++ ++#: system/settings/settings.xml ++msgctxt "#37033" ++msgid "Select omxplayer or dvdplayer automatically" ++msgstr "" ++ ++#: system/settings/settings.xml ++msgctxt "#37034" ++msgid "Uses codec information and audio setting to choose dvdplayer or omxplayer as appropriate" ++msgstr "" +diff --git a/system/settings/settings.xml b/system/settings/settings.xml +index f87373a..bd7858e 100644 +--- a/system/settings/settings.xml ++++ b/system/settings/settings.xml +@@ -757,6 +757,15 @@ + true + + ++ ++ HAS_OMXPLAYER ++ ++ 1 ++ ++ 2 ++ true ++ ++ + + HAS_OMXPLAYER + +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp +index de49617..b274756 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp +@@ -490,6 +490,62 @@ void CSelectionStreams::Update(CDVDInputStream* input, CDVDDemux* demuxer) + + void CDVDPlayer::CreatePlayers() + { ++#ifdef HAS_OMXPLAYER ++ bool omxplayer_mode = m_omxplayer_mode; ++ bool autoomx = CSettings::Get().GetBool("videoplayer.autoomxplayer"); ++ // omxplayer only handles Pi sink ++ if (autoomx && m_omxplayer_mode && ++ CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue" && ++ CSettings::Get().GetString("audiooutput.audiodevice") != "PI:HDMI") ++ { ++ CLog::Log(LOGNOTICE, "COMXPlayer::%s OMXPlayer unsuitable due to audio sink", __func__); ++ m_omxplayer_mode = false; ++ } ++ if (autoomx && m_pDemuxer && m_omxplayer_mode) ++ { ++ // find video stream ++ int num_supported = 0, num_unsupported = 0; ++ AVCodecID codec = AV_CODEC_ID_NONE; ++ SelectionStreams streams = m_SelectionStreams.Get(STREAM_VIDEO, PredicateVideoPriority); ++ for(SelectionStreams::iterator it = streams.begin(); it != streams.end(); ++it) ++ { ++ int iStream = it->id; ++ CDemuxStream *stream = m_pDemuxer->GetStream(iStream); ++ if(!stream || stream->disabled) ++ continue; ++ CDVDStreamInfo hint(*stream, true); ++ ++ bool supported = false; ++ if ((hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO) && g_RBP.GetCodecMpg2()) ++ supported = true; ++ else if ((hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3) && g_RBP.GetCodecWvc1()) ++ supported = true; ++ else if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_MPEG4 || hint.codec == AV_CODEC_ID_H263 || ++ hint.codec == AV_CODEC_ID_VP6 || hint.codec == AV_CODEC_ID_VP6F || hint.codec == AV_CODEC_ID_VP6A || hint.codec == AV_CODEC_ID_VP8 || ++ hint.codec == AV_CODEC_ID_THEORA || hint.codec == AV_CODEC_ID_MJPEG || hint.codec == AV_CODEC_ID_MJPEGB) ++ supported = true; ++ codec = hint.codec; ++ if (supported) ++ num_supported++; ++ else ++ num_unsupported++; ++ } ++ if (num_unsupported > 0 && num_supported == 0) ++ { ++ CLog::Log(LOGNOTICE, "COMXPlayer::%s OMXPlayer unsuitable due to video codec (%x:%d/%d)", __func__, codec, num_supported, num_unsupported); ++ m_omxplayer_mode = false; ++ } ++ } ++ if (autoomx && m_pInputStream && m_pInputStream->IsStreamType(DVDSTREAM_TYPE_DVD)) ++ { ++ CLog::Log(LOGNOTICE, "COMXPlayer::%s OMXPlayer unsuitable due to dvd menus", __func__); ++ m_omxplayer_mode = false; ++ } ++ ++ if (m_omxplayer_mode != omxplayer_mode) ++ DestroyPlayers(); ++#endif ++ + if (m_players_created) + return; + +@@ -1187,6 +1243,8 @@ void CDVDPlayer::Process() + m_bAbortRequest = true; + return; + } ++ // give players a chance to reconsider now codecs are known ++ CreatePlayers(); + + // allow renderer to switch to fullscreen if requested + m_dvdPlayerVideo->EnableFullscreen(m_PlayerOptions.fullscreen); + +From 03adf05c7efb63bd728dd31dbe7eeac7da0e247a Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 12 Aug 2014 16:51:18 +0100 +Subject: [PATCH 49/77] AE: Add some logging for suspend/resume + +--- + xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 5 +++++ + xbmc/cores/omxplayer/OMXAudio.cpp | 2 ++ + 2 files changed, 7 insertions(+) + +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +index fe5e893..3e89523 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -345,6 +345,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) + switch (signal) + { + case CActiveAEControlProtocol::INIT: ++ CLog::Log(LOGNOTICE, "CActiveAE::%s - AE_TOP_UNCONFIGURED/CActiveAEControlProtocol::INIT", __func__); + m_extError = false; + m_sink.EnumerateSinkList(false); + LoadSettings(); +@@ -430,6 +431,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) + m_extDeferData = true; + return; + case CActiveAEControlProtocol::SUSPEND: ++ CLog::Log(LOGNOTICE, "CActiveAE::%s - AE_TOP_CONFIGURED/CActiveAEControlProtocol::SUSPEND", __func__); + UnconfigureSink(); + m_stats.SetSuspended(true); + m_state = AE_TOP_CONFIGURED_SUSPEND; +@@ -655,6 +657,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) + CLog::Log(LOGDEBUG,"CActiveAE - display reset event"); + displayReset = true; + case CActiveAEControlProtocol::INIT: ++ CLog::Log(LOGNOTICE, "CActiveAE::%s - AE_TOP_CONFIGURED_SUSPEND/CActiveAEControlProtocol::INIT", __func__); + m_extError = false; + if (!displayReset) + { +@@ -2332,12 +2335,14 @@ void CActiveAE::Shutdown() + + bool CActiveAE::Suspend() + { ++ CLog::Log(LOGNOTICE, "ActiveAE::%s", __FUNCTION__); + return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND); + } + + bool CActiveAE::Resume() + { + Message *reply; ++ CLog::Log(LOGNOTICE, "ActiveAE::%s", __FUNCTION__); + if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT, + &reply, + 5000)) +diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp +index 7e85441..a73dd0a 100644 +--- a/xbmc/cores/omxplayer/OMXAudio.cpp ++++ b/xbmc/cores/omxplayer/OMXAudio.cpp +@@ -932,6 +932,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo + //*********************************************************************************************** + bool COMXAudio::Deinitialize() + { ++ CLog::Log(LOGNOTICE, "COMXAudio::%s start", __func__); + CSingleLock lock (m_critSection); + + if ( m_omx_tunnel_clock_analog.IsInitialized() ) +@@ -992,6 +993,7 @@ bool COMXAudio::Deinitialize() + m_submitted = 0.0f; + m_maxLevel = 0.0f; + ++ CLog::Log(LOGNOTICE, "COMXAudio::%s end", __func__); + return true; + } + + +From 7c39ab7b84943aeace23e0488b6f21b73ffc1653 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 9 Jul 2014 22:45:43 +0100 +Subject: [PATCH 50/77] [rbp] Make cachemembuffersize default depend on memory + size + +--- + xbmc/linux/RBP.cpp | 5 +++++ + xbmc/settings/AdvancedSettings.cpp | 5 +++++ + 2 files changed, 10 insertions(+) + +diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp +index 11376fc..b67fbb1 100644 +--- a/xbmc/linux/RBP.cpp ++++ b/xbmc/linux/RBP.cpp +@@ -22,6 +22,7 @@ + #if defined(TARGET_RASPBERRY_PI) + + #include "settings/Settings.h" ++#include "settings/AdvancedSettings.h" + #include "utils/log.h" + + #include "cores/omxplayer/OMXImage.h" +@@ -84,6 +85,9 @@ bool CRBP::Initialize() + if (!m_gui_resolution_limit) + m_gui_resolution_limit = m_gpu_mem < 128 ? 720:1080; + ++ if (g_advancedSettings.m_cacheMemBufferSize == ~0) ++ g_advancedSettings.m_cacheMemBufferSize = m_arm_mem < 256 ? 1024 * 1024 * 2 : 1024 * 1024 * 20; ++ + g_OMXImage.Initialize(); + m_omx_image_init = true; + return true; +@@ -96,6 +100,7 @@ void CRBP::LogFirmwareVerison() + response[sizeof(response) - 1] = '\0'; + CLog::Log(LOGNOTICE, "Raspberry PI firmware version: %s", response); + CLog::Log(LOGNOTICE, "ARM mem: %dMB GPU mem: %dMB MPG2:%d WVC1:%d", m_arm_mem, m_gpu_mem, m_codec_mpg2_enabled, m_codec_wvc1_enabled); ++ CLog::Log(LOGNOTICE, "cacheMemBufferSize: %dMB", g_advancedSettings.m_cacheMemBufferSize >> 20); + m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config int"); + response[sizeof(response) - 1] = '\0'; + CLog::Log(LOGNOTICE, "Config:\n%s", response); +diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp +index 4af3c7a..c003c5a 100644 +--- a/xbmc/settings/AdvancedSettings.cpp ++++ b/xbmc/settings/AdvancedSettings.cpp +@@ -364,7 +364,12 @@ void CAdvancedSettings::Initialize() + + m_measureRefreshrate = false; + ++#ifdef TARGET_RASPBERRY_PI ++ // want default to be memory dependent, but interface to gpu not available yet, so set in RBP.cpp ++ m_cacheMemBufferSize = ~0; ++#else + m_cacheMemBufferSize = 1024 * 1024 * 20; ++#endif + m_networkBufferMode = 0; // Default (buffer all internet streams/filesystems) + // the following setting determines the readRate of a player data + // as multiply of the default data read rate + +From 8f2f06af909adfada148cca51e9195b9461a037c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 16 Jun 2014 19:06:00 +0100 -Subject: [PATCH 66/98] [experimental] Disable quiet-noise generation +Subject: [PATCH 53/77] [experimental] Disable quiet-noise generation --- xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp | 2 ++ @@ -11847,56 +10807,36 @@ index 488a0df..d9f4a43 100644 } void CActiveAESink::SetSilenceTimer() --- -2.0.4 - -From d027aead2fa510c5377b247c209e34f18d50ea3b Mon Sep 17 00:00:00 2001 +From 0a2b78734e0e04fbc18edbfd7efc0813c98715ae Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Mon, 16 Jun 2014 19:07:21 +0100 -Subject: [PATCH 67/98] [omxcodec] Adjust asserts +Date: Fri, 30 May 2014 14:58:43 +0100 +Subject: [PATCH 54/77] [settings] Experiment: Report DESKTOP resolution in + video settings --- - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) + xbmc/settings/DisplaySettings.cpp | 3 +++ + 1 file changed, 3 insertions(+) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -index 494fdf5..23aaa9f 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp -@@ -795,7 +795,7 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) - // only push if we are successful with feeding OMX_EmptyThisBuffer - pthread_mutex_lock(&m_omx_output_mutex); - m_dts_queue.push(dts); -- assert(m_dts_queue.size() < 32); -+ assert(m_dts_queue.size() < 64); - pthread_mutex_unlock(&m_omx_output_mutex); - } - #endif -@@ -1037,9 +1037,12 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone( - if ((!m_deinterlace || (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD)) && buffer->omx_buffer->nFlags) - { - pthread_mutex_lock(&m_omx_output_mutex); -- assert(!m_dts_queue.empty()); -- buffer->dts = m_dts_queue.front(); -- m_dts_queue.pop(); -+ if (!m_dts_queue.empty()) -+ { -+ buffer->dts = m_dts_queue.front(); -+ m_dts_queue.pop(); -+ } -+ else assert(0); - pthread_mutex_unlock(&m_omx_output_mutex); - } - #endif --- -2.0.4 +diff --git a/xbmc/settings/DisplaySettings.cpp b/xbmc/settings/DisplaySettings.cpp +index bb31f15..eae549b 100644 +--- a/xbmc/settings/DisplaySettings.cpp ++++ b/xbmc/settings/DisplaySettings.cpp +@@ -650,6 +650,9 @@ void CDisplaySettings::SettingOptionsResolutionsFiller(const CSetting *setting, + vector resolutions = g_Windowing.ScreenResolutions(info.iScreen, info.fRefreshRate); + for (vector::const_iterator resolution = resolutions.begin(); resolution != resolutions.end(); ++resolution) + { ++if (resolution->ResInfo_Index == RES_DESKTOP) ++ list.push_back(make_pair(StringUtils::Format("DESKTOP"), resolution->ResInfo_Index)); ++else + list.push_back(make_pair( + StringUtils::Format("%dx%d%s", resolution->width, resolution->height, + ModeFlagsToString(resolution->flags, false).c_str()), - -From 6e7116f994f19a6373d65827a7e0a13eab8f2598 Mon Sep 17 00:00:00 2001 +From 069d3bbd3f6fb99311923b22001faa2e1d53b106 Mon Sep 17 00:00:00 2001 From: macrule Date: Thu, 11 Apr 2013 18:24:42 +0200 -Subject: [PATCH 68/98] Added some vc_tv_* functions that were missing in +Subject: [PATCH 55/77] Added some vc_tv_* functions that were missing in DllBCM. --- @@ -11930,14 +10870,11 @@ index b92fdb8..9c7e293 100644 virtual int vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate, HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) { return ::vc_tv_hdmi_power_on_best(width, height, frame_rate, scan_mode, match_flags); }; --- -2.0.4 - -From 54fc8bbcf415b16051a1a32c16c0262d190fc234 Mon Sep 17 00:00:00 2001 +From f0c6be3fc275077081157e3bece35c6718c57559 Mon Sep 17 00:00:00 2001 From: macrule Date: Thu, 11 Apr 2013 18:29:03 +0200 -Subject: [PATCH 69/98] Added private utility function to map a float display +Subject: [PATCH 56/77] Added private utility function to map a float display aspect, to the respective SDTV_ASPECT_* enum value. --- @@ -11974,14 +10911,11 @@ index bf1e589..518a87d 100644 #endif bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector &resolutions) --- -2.0.4 - -From c1835ac2ae92eed9be9a2ec91fade3572335efef Mon Sep 17 00:00:00 2001 +From 24cd5274f8465c64f3f984fa5a1ada139f1d762a Mon Sep 17 00:00:00 2001 From: macrule Date: Thu, 11 Apr 2013 19:50:58 +0200 -Subject: [PATCH 70/98] Changed SDTV resolutions to be treated similarly to +Subject: [PATCH 57/77] Changed SDTV resolutions to be treated similarly to HDMI resolutions in SetNativeResolution. This means that the SDTV interface is powered up and set to the right mode. @@ -12077,14 +11011,11 @@ index 59401f5..a0acb1a 100644 RESOLUTION_INFO m_desktopRes; int m_width; int m_height; --- -2.0.4 - -From 0f6c3f7714fb247b7bfa279c34eb0f32e177de28 Mon Sep 17 00:00:00 2001 +From f068e06b096f1d09070abe714dcb9da4aeb41130 Mon Sep 17 00:00:00 2001 From: macrule Date: Thu, 11 Apr 2013 19:54:59 +0200 -Subject: [PATCH 71/98] Added methods SuspendVideoOutput() and +Subject: [PATCH 58/77] Added methods SuspendVideoOutput() and ResumeVideoOutput() to CRBP class, which can be used to power down the Raspberry PI's video interface, and restore it at a later point. @@ -12095,10 +11026,10 @@ Subject: [PATCH 71/98] Added methods SuspendVideoOutput() and 3 files changed, 21 insertions(+) diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index 73a42c4..e03d673 100644 +index b67fbb1..2ff6078 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp -@@ -173,4 +173,19 @@ void CRBP::Deinitialize() +@@ -212,4 +212,19 @@ void CRBP::Deinitialize() m_initialized = false; m_omx_initialized = false; } @@ -12119,12 +11050,12 @@ index 73a42c4..e03d673 100644 + #endif diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h -index e9a2d5a..04ddaa0 100644 +index 4fd18f3..f947acc 100644 --- a/xbmc/linux/RBP.h +++ b/xbmc/linux/RBP.h -@@ -58,6 +58,9 @@ class CRBP - unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true); +@@ -59,6 +59,9 @@ class CRBP DllOMX *GetDllOMX() { return m_OMX ? m_OMX->GetDll() : NULL; } + void WaitVsync(); + void SuspendVideoOutput(); + void ResumeVideoOutput(); @@ -12147,14 +11078,11 @@ index 9dc39d5..ca36082 100644 CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI() { --- -2.0.4 - -From 8f058a071f95c0f9666c4fc2a03bb20e549b9db8 Mon Sep 17 00:00:00 2001 +From 35cc5ae9e5e5914c0084a79cc6bd41853a59e086 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 11 Aug 2013 15:03:36 +0100 -Subject: [PATCH 72/98] PowerManager (and its IPowerSyscall instance) now gets +Subject: [PATCH 59/77] PowerManager (and its IPowerSyscall instance) now gets called from CApplication::OnKey() and can process and suppress key presses. This is a requirement to implement a virtual sleep state. @@ -12166,7 +11094,7 @@ Subject: [PATCH 72/98] PowerManager (and its IPowerSyscall instance) now gets 4 files changed, 23 insertions(+) diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 479b54a..64e2ec5 100644 +index 94ee013..e68c80f 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -2358,6 +2358,13 @@ bool CApplication::OnKey(const CKey& key) @@ -12246,14 +11174,11 @@ index 0b1f10a..e42b143 100644 private: void OnSleep(); void OnWake(); --- -2.0.4 - -From f9b3d1b57d33564ad380bc2728a3b9b33ec85777 Mon Sep 17 00:00:00 2001 +From 4ba5eadbae5505f85254ad58f3abb0a8a6d7ff62 Mon Sep 17 00:00:00 2001 From: macrule Date: Wed, 17 Apr 2013 13:23:01 +0200 -Subject: [PATCH 73/98] Added CPowerSyscallVirtualSleep class, which acts as a +Subject: [PATCH 60/77] Added CPowerSyscallVirtualSleep class, which acts as a base class for devices that have no native standby mode, and need to fake it in some way. @@ -12428,14 +11353,11 @@ index 0000000..ef6e682 +}; + +#endif // _POWER_SYSCALL_VIRTUAL_SLEEP_H_ --- -2.0.4 - -From 856baa2c34d05a1f7728ee5945b59942b292b1b9 Mon Sep 17 00:00:00 2001 +From 53a5805f8e8e2d24b35a50c8a6733898d4a5a375 Mon Sep 17 00:00:00 2001 From: macrule Date: Wed, 17 Apr 2013 13:24:22 +0200 -Subject: [PATCH 74/98] Added power management support for the Raspberry Pi. +Subject: [PATCH 61/77] Added power management support for the Raspberry Pi. Since it doesn't support true standby, we fake it by turning video on or off, and ignoring remote inputs during the standby phase. @@ -12580,14 +11502,11 @@ index 0000000..fd1d67c +#endif // TARGET_RASPBERRY_PI + +#endif // _RASPBERRY_PI_POWER_SYSCALL_H_ --- -2.0.4 - -From 573bae2c2c516d7fb46288e5b2846e6bf3e7a6d8 Mon Sep 17 00:00:00 2001 +From 514c8d47d50d43d065ec77ef3f7fa34e3d465a9b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 3 Mar 2014 16:16:29 +0000 -Subject: [PATCH 75/98] [power] hack - don't kill lirc or cec +Subject: [PATCH 62/77] [power] hack - don't kill lirc or cec --- xbmc/peripherals/devices/PeripheralCecAdapter.cpp | 37 +++++++++++++++++++++++ @@ -12670,14 +11589,11 @@ index 2d8c750..901f449 100644 CLog::Log(LOGNOTICE, "%s: Restarting lirc", __FUNCTION__); CBuiltins::Execute("LIRC.Start"); #endif --- -2.0.4 - -From b5fe7c1d7495722c8cd74b38dfde5cca6b05feb9 Mon Sep 17 00:00:00 2001 +From 3e41f1b5cd582be0b60a630cc00418cdbed3825a Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 3 Mar 2014 16:47:54 +0000 -Subject: [PATCH 76/98] [power] hack - wake on any action +Subject: [PATCH 63/77] [power] hack - wake on any action --- xbmc/powermanagement/PowerSyscallVirtualSleep.cpp | 6 +++--- @@ -12705,14 +11621,11 @@ index 6a1e47b..a717a09 100644 { if(VirtualWake()) { --- -2.0.4 - -From 6a8fc76641a6f2795ac6140c084602d6a8d8426e Mon Sep 17 00:00:00 2001 +From 02a91126f1e132933a7e51e6d667a6824f81379f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 3 Mar 2014 17:30:07 +0000 -Subject: [PATCH 77/98] [power] hack - Make suspend toggle suspend state +Subject: [PATCH 64/77] [power] hack - Make suspend toggle suspend state --- xbmc/powermanagement/PowerSyscallVirtualSleep.cpp | 5 +++++ @@ -12734,14 +11647,11 @@ index a717a09..d39c3ed 100644 return false; } --- -2.0.4 - -From 0c17646f0402a7c85e3d65d01658d65362ba4a2a Mon Sep 17 00:00:00 2001 +From 3c3d10199293eaf3cba04ca241c9dfb77a9c5475 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 4 Mar 2014 19:33:44 +0000 -Subject: [PATCH 78/98] [power] Add back in powerdown and reboot +Subject: [PATCH 65/77] [power] Add back in powerdown and reboot --- .../linux/RaspberryPIPowerSyscall.cpp | 34 ++++++++++++++++++++++ @@ -12818,26 +11728,506 @@ index fd1d67c..062132e 100644 virtual bool CanHibernate() { return false; } virtual bool CanReboot() { return true; } --- -2.0.4 +From 5187a8e86050670abd3669590383f2f9958eef5d Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Sat, 26 Apr 2014 17:27:52 +0100 +Subject: [PATCH 70/77] [cec] Don't suspend pi on tv switch off - it can't wake + up -From 3ff5ea0b890dfc53921f7473ab513ca5c664ae58 Mon Sep 17 00:00:00 2001 +--- + system/peripherals.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/system/peripherals.xml b/system/peripherals.xml +index a906628..9b5271a 100644 +--- a/system/peripherals.xml ++++ b/system/peripherals.xml +@@ -16,7 +16,7 @@ + + + +- ++ + + + + +From 63179060ddac85446753a50f4b8a92e899cbc944 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 18 Aug 2014 19:09:32 +0100 +Subject: [PATCH 71/77] rbp: Use new dispmanx function for vsync callbacks + +--- + xbmc/linux/RBP.cpp | 85 ++++++++++++++----------- + xbmc/linux/RBP.h | 5 +- + xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +- + 3 files changed, 52 insertions(+), 42 deletions(-) + +diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp +index 2ff6078..360fc39 100644 +--- a/xbmc/linux/RBP.cpp ++++ b/xbmc/linux/RBP.cpp +@@ -33,7 +33,7 @@ CRBP::CRBP() + m_omx_initialized = false; + m_DllBcmHost = new DllBcmHost(); + m_OMX = new COMXCore(); +- m_element = 0; ++ m_display = DISPMANX_NO_HANDLE; + } + + CRBP::~CRBP() +@@ -55,8 +55,7 @@ bool CRBP::Initialize() + + m_DllBcmHost->bcm_host_init(); + +- uint32_t vc_image_ptr; +- m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr ); ++ //OpenDisplay(0 /*screen*/); + + m_omx_initialized = m_OMX->Initialize(); + if(!m_omx_initialized) +@@ -109,13 +108,24 @@ void CRBP::LogFirmwareVerison() + CLog::Log(LOGNOTICE, "Config:\n%s", response); + } + ++DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device) ++{ ++ if (m_display == DISPMANX_NO_HANDLE) ++ m_display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ return m_display; ++} ++ ++void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display) ++{ ++ assert(display == m_display); ++ vc_dispmanx_display_close(m_display); ++ m_display = DISPMANX_NO_HANDLE; ++} ++ + void CRBP::GetDisplaySize(int &width, int &height) + { +- DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_MODEINFO_T info; +- +- display = vc_dispmanx_display_open( 0 /*screen*/ ); +- if (vc_dispmanx_display_get_info(display, &info) == 0) ++ if (vc_dispmanx_display_get_info(m_display, &info) == 0) + { + width = info.width; + height = info.height; +@@ -125,12 +135,10 @@ void CRBP::GetDisplaySize(int &width, int &height) + width = 0; + height = 0; + } +- vc_dispmanx_display_close(display ); + } + + unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only) + { +- DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_RESOURCE_HANDLE_T resource; + VC_RECT_T rect; + unsigned char *image = NULL; +@@ -145,7 +153,6 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + if (!pstride) + flags |= DISPMANX_SNAPSHOT_PACK; + +- display = vc_dispmanx_display_open( 0 /*screen*/ ); + stride = ((width + 15) & ~15) * 4; + image = new unsigned char [height * stride]; + +@@ -153,45 +160,44 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + { + resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr ); + +- vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags); ++ assert(m_display != DISPMANX_NO_HANDLE); ++ vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags); + + vc_dispmanx_rect_set(&rect, 0, 0, width, height); + vc_dispmanx_resource_read_data(resource, &rect, image, stride); + vc_dispmanx_resource_delete( resource ); +- vc_dispmanx_display_close(display ); + } + if (pstride) + *pstride = stride; + return image; + } + +-void CRBP::WaitVsync(void) ++ ++static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg) ++{ ++ CEvent *sync = (CEvent *)arg; ++ sync->Set(); ++} ++ ++void CRBP::WaitVsync() + { +- DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ ); +- DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); +- +- VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 }; +- VC_RECT_T src_rect; +- VC_RECT_T dst_rect; +- vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 ); +- vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 ); +- +- if (m_element) +- vc_dispmanx_element_remove( update, m_element ); +- +- m_element = vc_dispmanx_element_add( update, +- display, +- 2000, // layer +- &dst_rect, +- m_resource, +- &src_rect, +- DISPMANX_PROTECTION_NONE, +- &alpha, +- NULL, // clamp +- (DISPMANX_TRANSFORM_T)0 ); +- +- vc_dispmanx_update_submit_sync(update); +- vc_dispmanx_display_close( display ); ++ int s; ++ CEvent sync; ++ DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ if (m_display == DISPMANX_NO_HANDLE) ++ { ++ CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__); ++ return; ++ } ++ s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&sync); ++ if (s == 0) ++ { ++ sync.Wait(); ++ } ++ else assert(0); ++ s = vc_dispmanx_vsync_callback(m_display, NULL, NULL); ++ assert(s == 0); ++ vc_dispmanx_display_close( m_display ); + } + + +@@ -203,6 +209,9 @@ void CRBP::Deinitialize() + if(m_omx_initialized) + m_OMX->Deinitialize(); + ++ if (m_display) ++ CloseDisplay(m_display); ++ + m_DllBcmHost->bcm_host_deinit(); + + if(m_initialized) +diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h +index f947acc..ca80045 100644 +--- a/xbmc/linux/RBP.h ++++ b/xbmc/linux/RBP.h +@@ -53,6 +53,8 @@ class CRBP + bool GetCodecMpg2() { return m_codec_mpg2_enabled; } + bool GetCodecWvc1() { return m_codec_wvc1_enabled; } + void GetDisplaySize(int &width, int &height); ++ DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device); ++ void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display); + int GetGUIResolutionLimit() { return m_gui_resolution_limit; } + // stride can be null for packed output + unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true); +@@ -73,10 +75,9 @@ class CRBP + bool m_codec_mpg2_enabled; + bool m_codec_wvc1_enabled; + COMXCore *m_OMX; +- DISPMANX_RESOURCE_HANDLE_T m_resource; +- DISPMANX_ELEMENT_HANDLE_T m_element; + class DllLibOMXCore; + CCriticalSection m_critSection; ++ DISPMANX_DISPLAY_HANDLE_T m_display; + }; + + extern CRBP g_RBP; +diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +index ca36082..4b74ea0 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res) + m_desktopRes = res; + } + +- m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0); ++ m_dispman_display = g_RBP.OpenDisplay(0); + + m_width = res.iWidth; + m_height = res.iHeight; +@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow() + + if (m_dispman_display != DISPMANX_NO_HANDLE) + { +- m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display); ++ g_RBP.CloseDisplay(m_dispman_display); + m_dispman_display = DISPMANX_NO_HANDLE; + } + DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n"); + +From d929ed74688c7b51f0281f9d9641581c4c687180 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 19 Aug 2014 17:56:45 +0100 +Subject: [PATCH 72/77] Revert "rbp: Use new dispmanx function for vsync + callbacks" + +This reverts commit afbf8fbceaa6649fb4a6bbd9a1cee6087590412b. +--- + xbmc/linux/RBP.cpp | 85 +++++++++++-------------- + xbmc/linux/RBP.h | 5 +- + xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +- + 3 files changed, 42 insertions(+), 52 deletions(-) + +diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp +index 360fc39..2ff6078 100644 +--- a/xbmc/linux/RBP.cpp ++++ b/xbmc/linux/RBP.cpp +@@ -33,7 +33,7 @@ CRBP::CRBP() + m_omx_initialized = false; + m_DllBcmHost = new DllBcmHost(); + m_OMX = new COMXCore(); +- m_display = DISPMANX_NO_HANDLE; ++ m_element = 0; + } + + CRBP::~CRBP() +@@ -55,7 +55,8 @@ bool CRBP::Initialize() + + m_DllBcmHost->bcm_host_init(); + +- //OpenDisplay(0 /*screen*/); ++ uint32_t vc_image_ptr; ++ m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr ); + + m_omx_initialized = m_OMX->Initialize(); + if(!m_omx_initialized) +@@ -108,24 +109,13 @@ void CRBP::LogFirmwareVerison() + CLog::Log(LOGNOTICE, "Config:\n%s", response); + } + +-DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device) +-{ +- if (m_display == DISPMANX_NO_HANDLE) +- m_display = vc_dispmanx_display_open( 0 /*screen*/ ); +- return m_display; +-} +- +-void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display) +-{ +- assert(display == m_display); +- vc_dispmanx_display_close(m_display); +- m_display = DISPMANX_NO_HANDLE; +-} +- + void CRBP::GetDisplaySize(int &width, int &height) + { ++ DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_MODEINFO_T info; +- if (vc_dispmanx_display_get_info(m_display, &info) == 0) ++ ++ display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ if (vc_dispmanx_display_get_info(display, &info) == 0) + { + width = info.width; + height = info.height; +@@ -135,10 +125,12 @@ void CRBP::GetDisplaySize(int &width, int &height) + width = 0; + height = 0; + } ++ vc_dispmanx_display_close(display ); + } + + unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only) + { ++ DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_RESOURCE_HANDLE_T resource; + VC_RECT_T rect; + unsigned char *image = NULL; +@@ -153,6 +145,7 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + if (!pstride) + flags |= DISPMANX_SNAPSHOT_PACK; + ++ display = vc_dispmanx_display_open( 0 /*screen*/ ); + stride = ((width + 15) & ~15) * 4; + image = new unsigned char [height * stride]; + +@@ -160,44 +153,45 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + { + resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr ); + +- assert(m_display != DISPMANX_NO_HANDLE); +- vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags); ++ vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags); + + vc_dispmanx_rect_set(&rect, 0, 0, width, height); + vc_dispmanx_resource_read_data(resource, &rect, image, stride); + vc_dispmanx_resource_delete( resource ); ++ vc_dispmanx_display_close(display ); + } + if (pstride) + *pstride = stride; + return image; + } + +- +-static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg) +-{ +- CEvent *sync = (CEvent *)arg; +- sync->Set(); +-} +- +-void CRBP::WaitVsync() ++void CRBP::WaitVsync(void) + { +- int s; +- CEvent sync; +- DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ ); +- if (m_display == DISPMANX_NO_HANDLE) +- { +- CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__); +- return; +- } +- s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&sync); +- if (s == 0) +- { +- sync.Wait(); +- } +- else assert(0); +- s = vc_dispmanx_vsync_callback(m_display, NULL, NULL); +- assert(s == 0); +- vc_dispmanx_display_close( m_display ); ++ DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); ++ ++ VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 }; ++ VC_RECT_T src_rect; ++ VC_RECT_T dst_rect; ++ vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 ); ++ vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 ); ++ ++ if (m_element) ++ vc_dispmanx_element_remove( update, m_element ); ++ ++ m_element = vc_dispmanx_element_add( update, ++ display, ++ 2000, // layer ++ &dst_rect, ++ m_resource, ++ &src_rect, ++ DISPMANX_PROTECTION_NONE, ++ &alpha, ++ NULL, // clamp ++ (DISPMANX_TRANSFORM_T)0 ); ++ ++ vc_dispmanx_update_submit_sync(update); ++ vc_dispmanx_display_close( display ); + } + + +@@ -209,9 +203,6 @@ void CRBP::Deinitialize() + if(m_omx_initialized) + m_OMX->Deinitialize(); + +- if (m_display) +- CloseDisplay(m_display); +- + m_DllBcmHost->bcm_host_deinit(); + + if(m_initialized) +diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h +index ca80045..f947acc 100644 +--- a/xbmc/linux/RBP.h ++++ b/xbmc/linux/RBP.h +@@ -53,8 +53,6 @@ class CRBP + bool GetCodecMpg2() { return m_codec_mpg2_enabled; } + bool GetCodecWvc1() { return m_codec_wvc1_enabled; } + void GetDisplaySize(int &width, int &height); +- DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device); +- void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display); + int GetGUIResolutionLimit() { return m_gui_resolution_limit; } + // stride can be null for packed output + unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true); +@@ -75,9 +73,10 @@ class CRBP + bool m_codec_mpg2_enabled; + bool m_codec_wvc1_enabled; + COMXCore *m_OMX; ++ DISPMANX_RESOURCE_HANDLE_T m_resource; ++ DISPMANX_ELEMENT_HANDLE_T m_element; + class DllLibOMXCore; + CCriticalSection m_critSection; +- DISPMANX_DISPLAY_HANDLE_T m_display; + }; + + extern CRBP g_RBP; +diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +index 4b74ea0..ca36082 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res) + m_desktopRes = res; + } + +- m_dispman_display = g_RBP.OpenDisplay(0); ++ m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0); + + m_width = res.iWidth; + m_height = res.iHeight; +@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow() + + if (m_dispman_display != DISPMANX_NO_HANDLE) + { +- g_RBP.CloseDisplay(m_dispman_display); ++ m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display); + m_dispman_display = DISPMANX_NO_HANDLE; + } + DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n"); + +From 587a18598ba8d407646394b8afa8e0aa66602cc8 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 20 Aug 2014 21:05:05 +0100 +Subject: [PATCH 73/77] [omxplayer] Use 0 for video timestamps when using + trickplay + +--- + xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +index c2bd788..2c0a86f 100644 +--- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp ++++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp +@@ -506,7 +506,10 @@ void OMXPlayerVideo::Process() + if (pts != DVD_NOPTS_VALUE) + pts += m_iVideoDelay; + +- m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pts); ++ if (m_speed != DVD_PLAYSPEED_NORMAL && m_speed != DVD_PLAYSPEED_PAUSE) ++ m_omxVideo.Decode(pPacket->pData, pPacket->iSize, 0.0); ++ else ++ m_omxVideo.Decode(pPacket->pData, pPacket->iSize, pts); + Output(pts, bRequestDrop); + if(pts != DVD_NOPTS_VALUE) + m_iCurrentPts = pts; + +From e2ed2cb0b3745661b74a1fdb8facaa9eaecd07b0 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 27 Jun 2014 00:01:05 +0100 -Subject: [PATCH 81/98] [rbp] Resume video output on startup +Subject: [PATCH 74/77] [rbp] Resume video output on startup --- xbmc/linux/RBP.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index e03d673..cea5ac5 100644 +index 2ff6078..34e0108 100644 --- a/xbmc/linux/RBP.cpp +++ b/xbmc/linux/RBP.cpp -@@ -80,6 +80,9 @@ bool CRBP::Initialize() - if (!m_gui_resolution_limit) - m_gui_resolution_limit = m_gpu_mem < 128 ? 720:1080; +@@ -88,6 +88,9 @@ bool CRBP::Initialize() + if (g_advancedSettings.m_cacheMemBufferSize == ~0) + g_advancedSettings.m_cacheMemBufferSize = m_arm_mem < 256 ? 1024 * 1024 * 2 : 1024 * 1024 * 20; + // in case xbcm was restarted when suspended + ResumeVideoOutput(); @@ -12845,988 +12235,395 @@ index e03d673..cea5ac5 100644 g_OMXImage.Initialize(); m_omx_image_init = true; return true; --- -2.0.4 - -From e0cfbf171e9a4c69bd67e5b507430ac1f7bad014 Mon Sep 17 00:00:00 2001 +From 1873caef5f16969652483140ce5b2365f3cc9887 Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Wed, 9 Jul 2014 22:45:43 +0100 -Subject: [PATCH 82/98] [rbp] Make cachemembuffersize default depend on memory - size +Date: Sat, 16 Aug 2014 21:01:42 +0100 +Subject: [PATCH 75/77] omxrender: Hacks to reduce GUI rendering rate when + playing video --- - xbmc/linux/RBP.cpp | 5 +++++ - xbmc/settings/AdvancedSettings.cpp | 5 +++++ - 2 files changed, 10 insertions(+) - -diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index cea5ac5..162b505 100644 ---- a/xbmc/linux/RBP.cpp -+++ b/xbmc/linux/RBP.cpp -@@ -22,6 +22,7 @@ - #if defined(TARGET_RASPBERRY_PI) - - #include "settings/Settings.h" -+#include "settings/AdvancedSettings.h" - #include "utils/log.h" - - #include "cores/omxplayer/OMXImage.h" -@@ -80,6 +81,9 @@ bool CRBP::Initialize() - if (!m_gui_resolution_limit) - m_gui_resolution_limit = m_gpu_mem < 128 ? 720:1080; - -+ if (g_advancedSettings.m_cacheMemBufferSize == ~0) -+ g_advancedSettings.m_cacheMemBufferSize = m_arm_mem < 256 ? 1024 * 1024 * 2 : 1024 * 1024 * 20; -+ - // in case xbcm was restarted when suspended - ResumeVideoOutput(); - -@@ -95,6 +99,7 @@ void CRBP::LogFirmwareVerison() - response[sizeof(response) - 1] = '\0'; - CLog::Log(LOGNOTICE, "Raspberry PI firmware version: %s", response); - CLog::Log(LOGNOTICE, "ARM mem: %dMB GPU mem: %dMB MPG2:%d WVC1:%d", m_arm_mem, m_gpu_mem, m_codec_mpg2_enabled, m_codec_wvc1_enabled); -+ CLog::Log(LOGNOTICE, "cacheMemBufferSize: %dMB", g_advancedSettings.m_cacheMemBufferSize >> 20); - m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config int"); - response[sizeof(response) - 1] = '\0'; - CLog::Log(LOGNOTICE, "Config:\n%s", response); -diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp -index 627080b..d5708ad 100644 ---- a/xbmc/settings/AdvancedSettings.cpp -+++ b/xbmc/settings/AdvancedSettings.cpp -@@ -364,7 +364,12 @@ void CAdvancedSettings::Initialize() - - m_measureRefreshrate = false; - -+#ifdef TARGET_RASPBERRY_PI -+ // want default to be memory dependent, but interface to gpu not available yet, so set in RBP.cpp -+ m_cacheMemBufferSize = ~0; -+#else - m_cacheMemBufferSize = 1024 * 1024 * 20; -+#endif - m_networkBufferMode = 0; // Default (buffer all internet streams/filesystems) - // the following setting determines the readRate of a player data - // as multiply of the default data read rate --- -2.0.4 - - -From 1100f74f57b5a6bd49b21fcc6509583a182d617e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 27 Jun 2014 00:36:29 +0100 -Subject: [PATCH 83/98] [omxplayer] Experimental support for anaglyph rendering - of 3d videos - -Requires updated firmware ---- - xbmc/cores/omxplayer/OMXPlayer.cpp | 12 +++++++-- - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 32 +++++++++++++++++++++++- - xbmc/cores/omxplayer/OMXVideo.cpp | 43 +++++++++++++++++++++------------ - xbmc/cores/omxplayer/OMXVideo.h | 3 ++- - xbmc/rendering/RenderSystem.cpp | 4 +++ - 5 files changed, 74 insertions(+), 20 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 62b671d..afeeb91 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -1503,6 +1503,8 @@ void CDVDPlayer::Process() - SetCaching(CACHESTATE_FLUSH); - - EDEINTERLACEMODE current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ RENDER_STEREO_MODE current_stereomode = g_graphicsContext.GetStereoMode(); -+ - float current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness; - SetSharpness(current_sharpness); - -@@ -1525,14 +1527,20 @@ void CDVDPlayer::Process() - float threshold = 0.1f; - bool audio_fifo_low = false, video_fifo_low = false, audio_fifo_high = false, video_fifo_high = false; - -- // if deinterlace setting has changed, we should close and open video -- if (current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode) -+ // if deinterlace or stereomode setting has changed, we should close and open video -+ RENDER_STEREO_MODE stereomode = g_graphicsContext.GetStereoMode(); -+ -+ if ((current_deinterlace != CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode) || -+ (current_stereomode != stereomode && -+ (current_stereomode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || current_stereomode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) != -+ (stereomode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || stereomode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA))) - { - CloseStream(m_CurrentVideo, false); - OpenStream(m_CurrentVideo, m_CurrentVideo.id, m_CurrentVideo.source); - if (m_State.canseek) - m_messenger.Put(new CDVDMsgPlayerSeek(GetTime(), true, true, true, true, true)); - current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ current_stereomode = stereomode; - } - - // if sharpness setting has changed, we should update it -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 811f087..050c62c 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -556,7 +556,29 @@ bool OMXPlayerVideo::OpenDecoder() - else - m_fForcedAspectRatio = 0.0; - -- bool bVideoDecoderOpen = m_omxVideo.Open(m_hints, m_av_clock, CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode, m_hdmi_clock_sync); -+ -+ unsigned flags = GetStereoModeFlags(GetStereoMode()); -+ RENDER_STEREO_MODE video_stereo_mode = (flags & CONF_FLAGS_STEREO_MODE_SBS) ? RENDER_STEREO_MODE_SPLIT_VERTICAL : -+ (flags & CONF_FLAGS_STEREO_MODE_TAB) ? RENDER_STEREO_MODE_SPLIT_HORIZONTAL : RENDER_STEREO_MODE_OFF; -+ bool stereo_invert = (flags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false; -+ OMX_IMAGEFILTERANAGLYPHTYPE anaglyph = OMX_ImageFilterAnaglyphNone; -+ -+ if (g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN) -+ { -+ if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) -+ anaglyph = OMX_ImageFilterAnaglyphSBStoRedCyan; -+ else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) -+ anaglyph = OMX_ImageFilterAnaglyphTABtoRedCyan; -+ } -+ else if (g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) -+ { -+ if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) -+ anaglyph = OMX_ImageFilterAnaglyphSBStoGreenMagenta; -+ else if (video_stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) -+ anaglyph = OMX_ImageFilterAnaglyphTABtoGreenMagenta; -+ } -+ -+ bool bVideoDecoderOpen = m_omxVideo.Open(m_hints, m_av_clock, CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode, anaglyph, m_hdmi_clock_sync); - m_omxVideo.RegisterResolutionUpdateCallBack((void *)this, ResolutionUpdateCallBack); - - if(!bVideoDecoderOpen) -@@ -701,6 +723,10 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec - video_stereo_mode = RENDER_STEREO_MODE_OFF; - display_stereo_mode = RENDER_STEREO_MODE_OFF; - } -+ else if (display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) -+ { -+ SrcRect.x2 *= 2.0f; -+ } - else if (stereo_invert) - { - SrcRect.x1 += m_hints.width / 2; -@@ -717,6 +743,10 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec - video_stereo_mode = RENDER_STEREO_MODE_OFF; - display_stereo_mode = RENDER_STEREO_MODE_OFF; - } -+ else if (display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN || display_stereo_mode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) -+ { -+ SrcRect.y2 *= 2.0f; -+ } - else if (stereo_invert) - { - SrcRect.y1 += m_hints.height / 2; -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index 7759da8..b100018 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -113,6 +113,7 @@ COMXVideo::COMXVideo() : m_video_codec_name("") - m_extrasize = 0; - m_deinterlace = false; - m_deinterlace_request = VS_DEINTERLACEMODE_OFF; -+ m_anaglyph = OMX_ImageFilterAnaglyphNone; - m_hdmi_clock_sync = false; - m_drop_state = false; - m_decoded_width = 0; -@@ -227,9 +228,9 @@ bool COMXVideo::PortSettingsChanged() - else - m_deinterlace = interlace.eMode != OMX_InterlaceProgressive; - -- CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__, -+ CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d anaglyph:%d", CLASSNAME, __func__, - port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight, -- port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace); -+ port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace, m_anaglyph); - - // let OMXPlayerVideo know about resolution so it can inform RenderManager - if (m_res_callback) -@@ -256,7 +257,7 @@ bool COMXVideo::PortSettingsChanged() - if(!m_omx_sched.Initialize("OMX.broadcom.video_scheduler", OMX_IndexParamVideoInit)) - return false; - -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - { - if(!m_omx_image_fx.Initialize("OMX.broadcom.image_fx", OMX_IndexParamImageInit)) - return false; -@@ -296,7 +297,7 @@ bool COMXVideo::PortSettingsChanged() - } - } - -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - { - bool advanced_deinterlace = port_image.format.video.nFrameWidth * port_image.format.video.nFrameHeight <= 576 * 720; - -@@ -319,13 +320,21 @@ bool COMXVideo::PortSettingsChanged() - OMX_INIT_STRUCTURE(image_filter); - - image_filter.nPortIndex = m_omx_image_fx.GetOutputPort(); -- image_filter.nNumParams = 1; -- image_filter.nParams[0] = 3; -- if (!advanced_deinterlace) -- image_filter.eImageFilter = OMX_ImageFilterDeInterlaceFast; -+ if (m_anaglyph != OMX_ImageFilterAnaglyphNone) -+ { -+ image_filter.nNumParams = 1; -+ image_filter.nParams[0] = m_anaglyph; -+ image_filter.eImageFilter = OMX_ImageFilterAnaglyph; -+ } - else -- image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced; -- -+ { -+ image_filter.nNumParams = 1; -+ image_filter.nParams[0] = 3; -+ if (!advanced_deinterlace) -+ image_filter.eImageFilter = OMX_ImageFilterDeInterlaceFast; -+ else -+ image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced; -+ } - omx_err = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter); - if(omx_err != OMX_ErrorNone) - { -@@ -334,7 +343,7 @@ bool COMXVideo::PortSettingsChanged() - } - } - -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - { - m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort()); - m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_sched, m_omx_sched.GetInputPort()); -@@ -361,7 +370,7 @@ bool COMXVideo::PortSettingsChanged() - return false; - } - -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - { - omx_err = m_omx_tunnel_image_fx.Establish(); - if(omx_err != OMX_ErrorNone) -@@ -403,7 +412,7 @@ bool COMXVideo::PortSettingsChanged() - return true; - } - --bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE deinterlace, bool hdmi_clock_sync) -+bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE deinterlace, OMX_IMAGEFILTERANAGLYPHTYPE anaglyph, bool hdmi_clock_sync) - { - CSingleLock lock (m_critSection); - bool vflip = false; -@@ -543,6 +552,7 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de - break; - } - m_deinterlace_request = deinterlace; -+ m_anaglyph = anaglyph; - - if(!m_omx_decoder.Initialize(decoder_name, OMX_IndexParamVideoInit)) - return false; -@@ -754,7 +764,7 @@ void COMXVideo::Close() - dump_omx_buffer(NULL); - m_omx_tunnel_clock.Deestablish(); - m_omx_tunnel_decoder.Deestablish(); -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - m_omx_tunnel_image_fx.Deestablish(); - m_omx_tunnel_sched.Deestablish(); - -@@ -762,7 +772,7 @@ void COMXVideo::Close() - - m_omx_sched.Deinitialize(); - m_omx_decoder.Deinitialize(); -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - m_omx_image_fx.Deinitialize(); - m_omx_render.Deinitialize(); - -@@ -775,6 +785,7 @@ void COMXVideo::Close() - - m_video_codec_name = ""; - m_deinterlace = false; -+ m_anaglyph = OMX_ImageFilterAnaglyphNone; - m_av_clock = NULL; - - m_res_ctx = NULL; -@@ -898,7 +909,7 @@ void COMXVideo::Reset(void) - - m_setStartTime = true; - m_omx_decoder.FlushInput(); -- if(m_deinterlace) -+ if(m_deinterlace || m_anaglyph) - m_omx_image_fx.FlushInput(); - } - -diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h -index 226000e..e2e79c2 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.h -+++ b/xbmc/cores/omxplayer/OMXVideo.h -@@ -49,7 +49,7 @@ class COMXVideo - - // Required overrides - bool SendDecoderConfig(); -- bool Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE deinterlace = VS_DEINTERLACEMODE_OFF, bool hdmi_clock_sync = false); -+ bool Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE deinterlace = VS_DEINTERLACEMODE_OFF, OMX_IMAGEFILTERANAGLYPHTYPE anaglyph = OMX_ImageFilterAnaglyphNone, bool hdmi_clock_sync = false); - bool PortSettingsChanged(); - void RegisterResolutionUpdateCallBack(void *ctx, ResolutionUpdateCallBackFn callback) { m_res_ctx = ctx; m_res_callback = callback; } - void Close(void); -@@ -94,6 +94,7 @@ class COMXVideo - - bool m_deinterlace; - EDEINTERLACEMODE m_deinterlace_request; -+ OMX_IMAGEFILTERANAGLYPHTYPE m_anaglyph; - bool m_hdmi_clock_sync; - ResolutionUpdateCallBackFn m_res_callback; - void *m_res_ctx; -diff --git a/xbmc/rendering/RenderSystem.cpp b/xbmc/rendering/RenderSystem.cpp -index 64e0d16..8a58893 100644 ---- a/xbmc/rendering/RenderSystem.cpp -+++ b/xbmc/rendering/RenderSystem.cpp -@@ -75,6 +75,10 @@ bool CRenderSystemBase::SupportsStereo(RENDER_STEREO_MODE mode) const - case RENDER_STEREO_MODE_SPLIT_HORIZONTAL: - case RENDER_STEREO_MODE_SPLIT_VERTICAL: - case RENDER_STEREO_MODE_MONO: -+#ifdef TARGET_RASPBERRY_PI -+ case RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN: -+ case RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA: -+#endif - return true; - default: - return false; --- -2.0.4 - - -From ec24d9ad4b3a22fe5a91521825bfd236e20ff764 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 2 Jul 2014 12:24:01 +0100 -Subject: [PATCH 84/98] [settings] Add update flag to omx acceleration - ---- - system/settings/settings.xml | 3 +++ - xbmc/settings/Settings.cpp | 1 + - 2 files changed, 4 insertions(+) - -diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index d69ffc0..fb358c1 100644 ---- a/system/settings/settings.xml -+++ b/system/settings/settings.xml -@@ -744,6 +744,9 @@ - - 2 - true -+ -+ -+ - - - -diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp -index 797e91a..c0ca299 100644 ---- a/xbmc/settings/Settings.cpp -+++ b/xbmc/settings/Settings.cpp -@@ -723,6 +723,7 @@ void CSettings::InitializeISettingCallbacks() - settingSet.insert("videoscreen.testpattern"); - settingSet.insert("videoplayer.useamcodec"); - settingSet.insert("videoplayer.usemediacodec"); -+ settingSet.insert("videoplayer.useomx"); - m_settingsManager->RegisterCallback(&g_application, settingSet); - - settingSet.clear(); --- -2.0.4 - - -From 3336eb304054aa32121128e0c3cbecfd2ac6ae73 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 2 Jul 2014 20:41:29 +0100 -Subject: [PATCH 85/98] [pi] Reduce time textures are held for when memory is - low - ---- - xbmc/Application.cpp | 9 +++++++++ - xbmc/linux/RBP.cpp | 10 ++++++++++ - xbmc/linux/RBP.h | 1 + - 3 files changed, 20 insertions(+) - -diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp -index 64e2ec5..7997e76 100644 ---- a/xbmc/Application.cpp -+++ b/xbmc/Application.cpp -@@ -345,6 +345,10 @@ - #include "utils/AMLUtils.h" - #endif - -+#if defined(TARGET_RASPBERRY_PI) -+#include "linux/RBP.h" -+#endif -+ - #include "cores/FFmpeg.h" - - using namespace std; -@@ -5180,6 +5184,11 @@ void CApplication::ProcessSlow() - if (!m_pPlayer->IsPlayingVideo()) - g_largeTextureManager.CleanupUnusedImages(); - -+#ifdef TARGET_RASPBERRY_PI -+ if (g_RBP.GetGpuMemFree() < 64) -+ g_TextureManager.FreeUnusedTextures(); -+ else -+#endif - g_TextureManager.FreeUnusedTextures(5000); - - #ifdef HAS_DVD_DRIVE -diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp -index 162b505..f26a7f1 100644 ---- a/xbmc/linux/RBP.cpp -+++ b/xbmc/linux/RBP.cpp -@@ -92,6 +92,16 @@ bool CRBP::Initialize() - return true; - } - -+int CRBP::GetGpuMemFree() -+{ -+ int reloc_mem = 0; -+ char response[80] = ""; -+ -+ if (vc_gencmd(response, sizeof response, "get_mem reloc") == 0) -+ vc_gencmd_number_property(response, "reloc", &reloc_mem); -+ return reloc_mem; -+} -+ - void CRBP::LogFirmwareVerison() - { - char response[1024]; -diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h -index 04ddaa0..3ad2327 100644 ---- a/xbmc/linux/RBP.h -+++ b/xbmc/linux/RBP.h -@@ -50,6 +50,7 @@ class CRBP - void Deinitialize(); - int GetArmMem() { return m_arm_mem; } - int GetGpuMem() { return m_gpu_mem; } -+ int GetGpuMemFree(); - bool GetCodecMpg2() { return m_codec_mpg2_enabled; } - bool GetCodecWvc1() { return m_codec_wvc1_enabled; } - void GetDisplaySize(int &width, int &height); --- -2.0.4 - - -From 6b15c342fae9bd19cf56e43bc2bb77ea44b318f3 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sat, 5 Jul 2014 19:26:46 +0100 -Subject: [PATCH 86/98] [omxplayer] Explictly choose deinterlace method for - 1080i - -As the 1080i deinterlace doesn't require the 3 frames of context we can save ~9MB by requesting it explicitly ---- - xbmc/cores/omxplayer/OMXVideo.cpp | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp -index b100018..15b62af 100644 ---- a/xbmc/cores/omxplayer/OMXVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp -@@ -301,9 +301,9 @@ bool COMXVideo::PortSettingsChanged() - { - bool advanced_deinterlace = port_image.format.video.nFrameWidth * port_image.format.video.nFrameHeight <= 576 * 720; - -- if (!advanced_deinterlace) -+ if (m_anaglyph != OMX_ImageFilterAnaglyphNone || !advanced_deinterlace) - { -- // Image_fx assumed 3 frames of context. simple deinterlace doesn't require this -+ // Image_fx assumed 3 frames of context. anaglyph and simple deinterlace don't require this - OMX_PARAM_U32TYPE extra_buffers; - OMX_INIT_STRUCTURE(extra_buffers); - extra_buffers.nU32 = -2; --- -2.0.4 - - -From 0faa2094befad4483f035df59faa9ade547e7c25 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 8 Jul 2014 21:00:44 +0100 -Subject: [PATCH 87/98] [omxcodec] Fix 3D rendering for dvdplayer - -Similar to https://github.com/xbmc/xbmc/pull/3887 ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 31 +++++++++++++++++++++---- - 1 file changed, 27 insertions(+), 4 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 53873f6..84a46ec 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -1369,10 +1369,11 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field) - } - - // Set texture coordinates -- tex[0][0] = tex[3][0] = 0; -- tex[0][1] = tex[1][1] = 0; -- tex[1][0] = tex[2][0] = 1; -- tex[2][1] = tex[3][1] = 1; -+ YUVPLANE &plane = m_buffers[index].fields[0][0]; -+ tex[0][0] = tex[3][0] = plane.rect.x1; -+ tex[0][1] = tex[1][1] = plane.rect.y1; -+ tex[1][0] = tex[2][0] = plane.rect.x2; -+ tex[2][1] = tex[3][1] = plane.rect.y2; - - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx); - -@@ -2506,6 +2507,7 @@ void CLinuxRendererGLES::UploadOMXEGLTexture(int index) - { - //buf.openMaxBuffer->Sync(); - } -+ CalculateTextureSourceRects(index, 1); - #endif - } - void CLinuxRendererGLES::DeleteOMXEGLTexture(int index) -@@ -2518,6 +2520,27 @@ void CLinuxRendererGLES::DeleteOMXEGLTexture(int index) - } - bool CLinuxRendererGLES::CreateOMXEGLTexture(int index) - { -+ YV12Image &im = m_buffers[index].image; -+ YUVFIELDS &fields = m_buffers[index].fields; -+ YUVPLANE &plane = fields[0][0]; -+ -+ memset(&im , 0, sizeof(im)); -+ memset(&fields, 0, sizeof(fields)); -+ -+ im.height = m_sourceHeight; -+ im.width = m_sourceWidth; -+ -+ plane.texwidth = im.width; -+ plane.texheight = im.height; -+ plane.pixpertex_x = 1; -+ plane.pixpertex_y = 1; -+ -+ if(m_renderMethod & RENDER_POT) -+ { -+ plane.texwidth = NP2(plane.texwidth); -+ plane.texheight = NP2(plane.texheight); -+ } -+ - DeleteOMXEGLTexture(index); - return true; - } --- -2.0.4 - - -From a02eba8b07d0165801997cd58e1c4a6941657bbc Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 13 Jul 2014 11:28:20 +0100 -Subject: [PATCH 88/98] [ResamplePi] Fix xbmc crash with usb audio when music - file switched - -Need to handle the case where AE requests fewer output samples that are produced. - -See: -http://forum.xbmc.org/showthread.php?tid=199244 -http://openelec.tv/forum/124-raspberry-pi/71119-openelec-4-0-1-crashes-after-each-song?start=15#110835 ---- - .../Engines/ActiveAE/ActiveAEResamplePi.cpp | 60 +++++++++++++++++----- - .../Engines/ActiveAE/ActiveAEResamplePi.h | 1 + - 2 files changed, 48 insertions(+), 13 deletions(-) - -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -index 1604030..08da688 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp -@@ -69,6 +69,7 @@ CActiveAEResample::CActiveAEResample() - m_last_dst_fmt = AV_SAMPLE_FMT_NONE; - m_last_src_channels = 0; - m_last_dst_channels = 0; -+ m_encoded_buffer = NULL; - } - - CActiveAEResample::~CActiveAEResample() -@@ -382,6 +383,14 @@ bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst - return true; - } - -+ -+static void copy_planes(uint8_t **dst_buffer, int d_pitch, int d_planes, int d_samplesize, int offset, uint8_t *src_buffer, int src_samples) -+{ -+ int planesize = src_samples * d_samplesize / d_planes; -+ for (int i=0; i < d_planes; i++) -+ memcpy(dst_buffer[i] + offset * d_pitch, src_buffer + i * planesize, planesize); -+} -+ - int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio) - { - #ifdef DEBUG_VERBOSE -@@ -398,21 +407,35 @@ int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t * - const int s_pitch = s_chans * m_src_bits >> 3; - const int d_pitch = d_chans * m_dst_bits >> 3; - -+ const int s_samplesize = m_src_channels * m_src_bits >> 3; -+ const int d_samplesize = m_dst_channels * m_dst_bits >> 3; -+ const int max_src_samples = BUFFERSIZE / s_samplesize; -+ const int max_dst_samples = (long long)(BUFFERSIZE / d_samplesize) * m_src_rate / (m_dst_rate + m_src_rate-1); -+ - int sent = 0; - int received = 0; -+ -+ if (m_encoded_buffer && m_encoded_buffer->nFilledLen) -+ { -+ int samples_available = m_encoded_buffer->nFilledLen / d_samplesize - m_encoded_buffer->nOffset; -+ int samples = std::min(samples_available, dst_samples - received); -+ copy_planes(dst_buffer, d_pitch, d_planes, d_samplesize, received, (uint8_t *)m_encoded_buffer->pBuffer + m_encoded_buffer->nOffset * d_pitch, samples); -+ received += samples; -+ samples_available -= samples; -+ if (samples_available > 0) -+ m_encoded_buffer->nOffset += samples; -+ else -+ m_encoded_buffer = NULL; -+ } -+ assert(!m_encoded_buffer); - while (sent < src_samples) - { - OMX_BUFFERHEADERTYPE *omx_buffer = NULL; -- OMX_BUFFERHEADERTYPE *m_encoded_buffer = NULL; - - omx_buffer = m_omx_mixer.GetInputBuffer(1000); - if (omx_buffer == NULL) - return false; - -- const int s_samplesize = m_src_channels * m_src_bits >> 3; -- const int d_samplesize = m_dst_channels * m_dst_bits >> 3; -- const int max_src_samples = BUFFERSIZE / s_samplesize; -- const int max_dst_samples = (long long)(BUFFERSIZE / d_samplesize) * m_src_rate / (m_dst_rate + m_src_rate-1); - int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent); - - omx_buffer->nOffset = 0; -@@ -464,22 +487,28 @@ int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t * - - if (m_encoded_buffer->nFilledLen) - { -- int planesize = m_encoded_buffer->nFilledLen / d_planes; -- for (int i=0; i < d_planes; i++) -- memcpy(dst_buffer[i] + received * d_pitch, (uint8_t *)m_encoded_buffer->pBuffer + i * planesize, planesize); -- received += m_encoded_buffer->nFilledLen / d_samplesize; -+ int samples_available = m_encoded_buffer->nFilledLen / d_samplesize; -+ int samples = std::min(samples_available, dst_samples - received); -+ copy_planes(dst_buffer, d_pitch, d_planes, d_samplesize, received, (uint8_t *)m_encoded_buffer->pBuffer, samples); -+ received += samples; -+ samples_available -= samples; -+ if (samples_available > 0) -+ m_encoded_buffer->nOffset += samples; -+ else -+ m_encoded_buffer = NULL; - } - } - #ifdef DEBUG_VERBOSE - CLog::Log(LOGINFO, "%s::%s format:%d->%d rate:%d->%d chan:%d->%d samples %d->%d (%f) %d =%d", CLASSNAME, __func__, - (int)m_src_fmt, (int)m_dst_fmt, m_src_rate, m_dst_rate, m_src_channels, m_dst_channels, src_samples, dst_samples, ratio, m_Initialized, received); - #endif -+ assert(received <= dst_samples); - return received; - } - - int64_t CActiveAEResample::GetDelay(int64_t base) - { -- int ret = 0; -+ int ret = m_dst_rate ? 1000 * GetBufferedSamples() / m_dst_rate : 0; - #ifdef DEBUG_VERBOSE - CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); - #endif -@@ -488,11 +517,16 @@ int64_t CActiveAEResample::GetDelay(int64_t base) - - int CActiveAEResample::GetBufferedSamples() - { -- int ret = 0; -+ int samples = 0; -+ if (m_encoded_buffer) -+ { -+ const int d_samplesize = m_dst_channels * m_dst_bits >> 3; -+ samples = m_encoded_buffer->nFilledLen / d_samplesize - m_encoded_buffer->nOffset; -+ } - #ifdef DEBUG_VERBOSE -- CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret); -+ CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, samples); - #endif -- return ret; -+ return samples; - } - - int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate) -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h -index 47a9e08..b88a90b 100644 ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h -@@ -57,6 +57,7 @@ class CActiveAEResample - bool m_Initialized; - AVSampleFormat m_last_src_fmt, m_last_dst_fmt; - int m_last_src_channels, m_last_dst_channels; -+ OMX_BUFFERHEADERTYPE *m_encoded_buffer; - }; - - } --- -2.0.4 - - -From 1b2f8b06f0bc3db1032672e334e390acde10a80b Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 10 Aug 2014 16:45:16 +0100 -Subject: [PATCH 91/98] filesystem: Make support of browsing into archives - optional - -The ability to browse, scan and play content in archives can cause problems on low powered/low memory devices. -It's quite common to see reports of a large rar file that causes xbmc to crash with an out-of-memory error when browsing or scanning. -It also can be slow as any archive in the directory is opened and extracted. - -Add a settings option to enable this feature and default to disabled on Pi ---- - language/English/strings.po | 10 ++++++++++ - system/settings/rbp.xml | 10 ++++++++++ - system/settings/settings.xml | 5 +++++ - xbmc/filesystem/FileDirectoryFactory.cpp | 4 ++++ - 4 files changed, 29 insertions(+) + language/English/strings.po | 27 +++++++++++++++++++++++++++ + system/settings/rbp.xml | 16 ++++++++++++++++ + xbmc/Application.cpp | 17 +++++++++++++++++ + 3 files changed, 60 insertions(+) diff --git a/language/English/strings.po b/language/English/strings.po -index a3ead30..b36e249 100755 +index 1b13a9b..06d425d 100755 --- a/language/English/strings.po +++ b/language/English/strings.po -@@ -15850,3 +15850,13 @@ msgstr "" - msgctxt "#37030" - msgid "Unlimited" +@@ -15894,3 +15894,30 @@ msgstr "" + msgctxt "#37034" + msgid "Uses codec information and audio setting to choose dvdplayer or omxplayer as appropriate" msgstr "" + +#: system/settings/settings.xml -+msgctxt "#37031" -+msgid "Support browsing into archives" ++msgctxt "#38000" ++msgid "Limit GUI updates when playing video" +msgstr "" + +#: system/settings/settings.xml -+msgctxt "#37032" -+msgid "Allow viewing and playing files in archives (e.g. zip, rar)" ++msgctxt "#38001" ++msgid "This can reduce CPU when playing video by updating the overlays less often" ++msgstr "" ++ ++#: system/settings/settings.xml ++msgctxt "#38002" ++msgid "Off" ++msgstr "" ++ ++msgctxt "#38003" ++msgid "5 fps" ++msgstr "" ++ ++msgctxt "#38004" ++msgid "10 fps" ++msgstr "" ++ ++msgctxt "#38005" ++msgid "24 fps" +msgstr "" diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml -index 60086d8..b65136a 100644 +index b65136a..9269dec 100644 --- a/system/settings/rbp.xml +++ b/system/settings/rbp.xml -@@ -1,5 +1,15 @@ - - -+
-+ -+ -+ -+ false +@@ -20,6 +20,22 @@ + false + + ++ ++ ++ 2 ++ 10 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + -+ -+
-+ -
- - -diff --git a/system/settings/settings.xml b/system/settings/settings.xml -index fb358c1..fdc44fb 100644 ---- a/system/settings/settings.xml -+++ b/system/settings/settings.xml -@@ -226,6 +226,11 @@ - false - - -+ -+ 1 -+ true -+ -+ - - -diff --git a/xbmc/filesystem/FileDirectoryFactory.cpp b/xbmc/filesystem/FileDirectoryFactory.cpp -index 2fd8777..3b294cd 100644 ---- a/xbmc/filesystem/FileDirectoryFactory.cpp -+++ b/xbmc/filesystem/FileDirectoryFactory.cpp -@@ -46,6 +46,7 @@ - #include "Directory.h" - #include "File.h" - #include "ZipManager.h" -+#include "settings/Settings.h" - #include "settings/AdvancedSettings.h" - #include "FileItem.h" - #include "utils/StringUtils.h" -@@ -142,6 +143,8 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, - return NULL; - } - #endif -+ if (CSettings::Get().GetBool("filelists.browsearchives")) +
+ +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index e68c80f..6a280d5 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2206,6 +2206,23 @@ void CApplication::Render() + if (m_bStop) + return; + ++#ifdef TARGET_RASPBERRY_PI ++ if (g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback()) + { - if (url.IsFileType("zip")) - { - CURL zipURL = URIUtils::CreateArchivePath("zip", url); -@@ -215,6 +218,7 @@ IFileDirectory* CFileDirectoryFactory::Create(const CURL& url, CFileItem* pItem, - } - return NULL; - } ++ int fps = CSettings::Get().GetInt("videoplayer.limitguiupdate"); ++ unsigned int now = XbmcThreads::SystemClockMillis(); ++ unsigned int frameTime = now - m_lastFrameTime; ++ if (fps > 0 && frameTime * fps < 1000) ++ { ++ g_renderManager.FrameWait(100); ++ g_infoManager.UpdateFPS(); ++ g_renderManager.FrameMove(); ++ g_renderManager.FrameFinish(); ++ return; ++ } + } - if (url.IsFileType("xsp")) - { // XBMC Smart playlist - just XML renamed to XSP - // read the name of the playlist in --- -2.0.4 - - -From 57d7dc731a7abdbee3928c750d8b3e6bb6030360 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 18 Aug 2014 23:16:28 +0100 -Subject: [PATCH 95/98] [omxplayer] Don't flush queued data on general reset - -We were flushing the queue of data to gpu (which can be a number of seconds worth) on a general reset. -However this is generated on inoccuous events like a chapter change in dvd playback. - -This results in a few seconds loss of audio, and a temporary audio/video sync error ---- - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 1 - - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 1 - - 2 files changed, 2 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -index 37b544c..cc6df28 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp -@@ -405,7 +405,6 @@ void OMXPlayerAudio::Process() - CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET"); - if (m_pAudioCodec) - m_pAudioCodec->Reset(); -- m_omxAudio.Flush(); - m_started = false; - m_audioClock = DVD_NOPTS_VALUE; - } -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -index 050c62c..5549bea 100644 ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp -@@ -392,7 +392,6 @@ void OMXPlayerVideo::Process() - else if (pMsg->IsType(CDVDMsg::GENERAL_RESET)) - { - CLog::Log(LOGDEBUG, "COMXPlayerVideo - CDVDMsg::GENERAL_RESET"); -- m_omxVideo.Reset(); - m_started = false; - m_nextOverlay = DVD_NOPTS_VALUE; - m_iCurrentPts = DVD_NOPTS_VALUE; --- -2.0.4 - - -From 19df499b9ba248ca943fd0f0d3c16fde7140b3e9 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 19 Aug 2014 00:53:17 +0100 -Subject: [PATCH 96/98] [dvdplayer] Allow UpdateCorrection to handle audio and - video jumping asynchronously - -This is sequence of timestamps (before correction) from The Grand Budapest Host chapter 3. - -12:07:04 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95502.94 pts: 95502.94 correction: 0.00 size: 46475 -12:07:04 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 95502.80 pts: 95502.80 correction: 0.00 size: 1792 -12:07:04 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95502.98 pts: 95502.98 correction: 0.00 size: 47057 -12:07:04 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.12 pts: 59.12 correction: 0.00 size: 1792 -12:07:04 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.12 pts: 59.12 correction: -95443.72 size: 1792 -12:07:04 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95503.03 pts: 0.00 correction: -95443.72 size: 60924 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.15 pts: 59.15 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.18 pts: 59.18 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95503.08 pts: 95503.08 correction: -95443.72 size: 46031 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.21 pts: 59.21 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95503.11 pts: 95503.11 correction: -95443.72 size: 43036 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.25 pts: 59.25 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95503.14 pts: 0.00 correction: -95443.72 size: 59193 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.28 pts: 59.28 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.31 pts: 59.31 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:2 dts: 59.49 pts: 59.49 correction: -95443.72 size: 4868 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.34 pts: 59.34 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.37 pts: 59.37 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95503.19 pts: 95503.19 correction: -95443.72 size: 42475 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.41 pts: 59.41 correction: -95443.72 size: 1792 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 59.53 pts: 59.56 correction: -95443.72 size: 49850 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:0 dts: 95503.24 pts: 95503.28 correction: -95443.72 size: 49850 -12:07:08 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.44 pts: 59.44 correction:-190887.44 size: 1792 -12:07:13 T:2730484832 DEBUG: CDVDPlayer::UpdateCorrection - stream:1 dts: 59.47 pts: 59.47 correction:-190887.44 size: 1792 - -Note that audio and video jump at different times. - -At the end of this correction should be -95443.72, but it actually jumps twice to double that. - -The timestamps arriving at PlayerVideo are not continuous, but jump from 95443 to 190887. - -This patch chooses to wait until audio and video have both jumped, and while only one has jumped, it gets timestamps of DVD_NOPTS_VALUE. - -This fixes the problem on my dvd, and appears to also fix this issue: -http://forum.xbmc.org/showthread.php?tid=201944 ---- - xbmc/cores/dvdplayer/DVDPlayer.cpp | 22 ++++++++++++++++------ - xbmc/cores/dvdplayer/DVDPlayer.h | 2 ++ - xbmc/cores/omxplayer/OMXPlayer.cpp | 22 ++++++++++++++++------ - xbmc/cores/omxplayer/OMXPlayer.h | 2 ++ - 4 files changed, 36 insertions(+), 12 deletions(-) - -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index afeeb91..d007d7d 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -596,6 +596,8 @@ bool CDVDPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) - m_State.Clear(); - m_UpdateApplication = 0; - m_offset_pts = 0; -+ m_CurrentAudio.correction = 0.0; -+ m_CurrentVideo.correction = 0.0; ++#endif ++ + MEASURE_FUNCTION; - m_PlayerOptions = options; - m_item = file; -@@ -2399,12 +2401,20 @@ return; + int vsync_mode = CSettings::Get().GetInt("videoscreen.vsync"); + +From eab1aae1889ddc167e7fb5702a750a3f9c492f77 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Fri, 29 Aug 2014 18:11:14 +0100 +Subject: [PATCH 76/77] omxcodec: experimental: enable deinterlace + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 11 ++++------- + xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h | 2 +- + 2 files changed, 5 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp +index 3218b63..84799e2 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp +@@ -115,7 +115,7 @@ COpenMaxVideo::COpenMaxVideo() + m_finished = false; + m_pFormatName = "mmal-xxxx"; - if(correction != 0.0) - { -- /* disable detection on next packet on other stream to avoid ping pong-ing */ -- if(m_CurrentAudio.player != current.player) m_CurrentAudio.dts = DVD_NOPTS_VALUE; -- if(m_CurrentVideo.player != current.player) m_CurrentVideo.dts = DVD_NOPTS_VALUE; -- -- m_offset_pts += correction; -- UpdateCorrection(pPacket, correction); -+ current.correction = correction; -+ if (m_CurrentAudio.correction != 0.0 && m_CurrentVideo.correction != 0.0 && fabs(m_CurrentAudio.correction - m_CurrentVideo.correction) < DVD_MSEC_TO_TIME(1000)) -+ { -+ m_offset_pts += correction; -+ UpdateCorrection(pPacket, correction); -+ m_CurrentAudio.correction = 0.0; -+ m_CurrentVideo.correction = 0.0; -+ } -+ else -+ { -+ // not sure yet - flags the packets as unknown until we get confirmation on another audio/video packet -+ pPacket->dts = DVD_NOPTS_VALUE; -+ pPacket->pts = DVD_NOPTS_VALUE; -+ } +- //m_interlace_mode = MMAL_InterlaceProgressive; ++ m_interlace_mode = MMAL_InterlaceProgressive; + m_startframe = false; + m_decoderPts = DVD_NOPTS_VALUE; + m_droppedPics = 0; +@@ -315,8 +315,6 @@ bool COpenMaxVideo::change_dec_output_format() + MMAL_STATUS_T status; + CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__); + +-#if 0 +- { + MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T interlace_type = {{ MMAL_PARAMETER_VIDEO_INTERLACE_TYPE, sizeof( interlace_type )}}; + status = mmal_port_parameter_get( m_dec_output, &interlace_type.hdr ); + +@@ -330,8 +328,7 @@ bool COpenMaxVideo::change_dec_output_format() } + else + CLog::Log(LOGERROR, "%s::%s Failed to query interlace type on %s (status=%x %s)", CLASSNAME, __func__, m_dec_output->name, status, mmal_status_to_string(status)); +- } +-#endif ++ + // todo: if we don't disable/enable we can do this from callback + mmal_format_copy(m_dec_output->format, m_es_format); + status = mmal_port_format_commit(m_dec_output); +@@ -870,7 +867,7 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) + } + } + EDEINTERLACEMODE deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +-#if 0 ++ if (1) + { + bool deinterlace = m_interlace_mode != MMAL_InterlaceProgressive; + +@@ -884,7 +881,7 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts) + else if (deinterlace && !m_deint) + CreateDeinterlace(); + } +-#endif ++ + if (buffer_to_free) + { + delete [] buffer_to_free; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h +index f931419..3c9b8a1 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h +@@ -133,7 +133,7 @@ class COpenMaxVideo + + CDVDStreamInfo m_hints; + // Components +- //MMAL_INTERLACETYPE_T m_interlace_mode; ++ MMAL_INTERLACETYPE_T m_interlace_mode; + bool m_startframe; + unsigned int m_decode_frame_number; + double m_decoderPts; + +From 2d19a382695fbc6c222f99a4870bfb003e321413 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Mon, 18 Aug 2014 19:09:32 +0100 +Subject: [PATCH 77/77] rbp: Use new dispmanx function for vsync callbacks + +--- + xbmc/linux/RBP.cpp | 85 ++++++++++++++----------- + xbmc/linux/RBP.h | 5 +- + xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 4 +- + 3 files changed, 52 insertions(+), 42 deletions(-) + +diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp +index 34e0108..462bfa2 100644 +--- a/xbmc/linux/RBP.cpp ++++ b/xbmc/linux/RBP.cpp +@@ -33,7 +33,7 @@ CRBP::CRBP() + m_omx_initialized = false; + m_DllBcmHost = new DllBcmHost(); + m_OMX = new COMXCore(); +- m_element = 0; ++ m_display = DISPMANX_NO_HANDLE; } -diff --git a/xbmc/cores/omxplayer/OMXPlayer.h b/xbmc/cores/omxplayer/OMXPlayer.h -index 7c1b34d..8e343c7 100644 ---- a/xbmc/cores/omxplayer/OMXPlayer.h -+++ b/xbmc/cores/omxplayer/OMXPlayer.h -@@ -72,6 +72,7 @@ class COMXCurrentStream - const int player; - // stuff to handle starting after seek - double startpts; -+ double correction; + CRBP::~CRBP() +@@ -55,8 +55,7 @@ bool CRBP::Initialize() - COMXCurrentStream(StreamType t, int i) - : type(t) -@@ -93,6 +94,7 @@ class COMXCurrentStream - inited = false; - started = false; - startpts = DVD_NOPTS_VALUE; -+ correction = 0.0; + m_DllBcmHost->bcm_host_init(); + +- uint32_t vc_image_ptr; +- m_resource = vc_dispmanx_resource_create( VC_IMAGE_RGB565, 1, 1, &vc_image_ptr ); ++ //OpenDisplay(0 /*screen*/); + + m_omx_initialized = m_OMX->Initialize(); + if(!m_omx_initialized) +@@ -112,13 +111,24 @@ void CRBP::LogFirmwareVerison() + CLog::Log(LOGNOTICE, "Config:\n%s", response); + } + ++DISPMANX_DISPLAY_HANDLE_T CRBP::OpenDisplay(uint32_t device) ++{ ++ if (m_display == DISPMANX_NO_HANDLE) ++ m_display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ return m_display; ++} ++ ++void CRBP::CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display) ++{ ++ assert(display == m_display); ++ vc_dispmanx_display_close(m_display); ++ m_display = DISPMANX_NO_HANDLE; ++} ++ + void CRBP::GetDisplaySize(int &width, int &height) + { +- DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_MODEINFO_T info; +- +- display = vc_dispmanx_display_open( 0 /*screen*/ ); +- if (vc_dispmanx_display_get_info(display, &info) == 0) ++ if (vc_dispmanx_display_get_info(m_display, &info) == 0) + { + width = info.width; + height = info.height; +@@ -128,12 +138,10 @@ void CRBP::GetDisplaySize(int &width, int &height) + width = 0; + height = 0; + } +- vc_dispmanx_display_close(display ); + } + + unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool swap_red_blue, bool video_only) + { +- DISPMANX_DISPLAY_HANDLE_T display; + DISPMANX_RESOURCE_HANDLE_T resource; + VC_RECT_T rect; + unsigned char *image = NULL; +@@ -148,7 +156,6 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + if (!pstride) + flags |= DISPMANX_SNAPSHOT_PACK; + +- display = vc_dispmanx_display_open( 0 /*screen*/ ); + stride = ((width + 15) & ~15) * 4; + image = new unsigned char [height * stride]; + +@@ -156,45 +163,44 @@ unsigned char *CRBP::CaptureDisplay(int width, int height, int *pstride, bool sw + { + resource = vc_dispmanx_resource_create( VC_IMAGE_RGBA32, width, height, &vc_image_ptr ); + +- vc_dispmanx_snapshot(display, resource, (DISPMANX_TRANSFORM_T)flags); ++ assert(m_display != DISPMANX_NO_HANDLE); ++ vc_dispmanx_snapshot(m_display, resource, (DISPMANX_TRANSFORM_T)flags); + + vc_dispmanx_rect_set(&rect, 0, 0, width, height); + vc_dispmanx_resource_read_data(resource, &rect, image, stride); + vc_dispmanx_resource_delete( resource ); +- vc_dispmanx_display_close(display ); + } + if (pstride) + *pstride = stride; + return image; + } + +-void CRBP::WaitVsync(void) ++ ++static void vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *arg) ++{ ++ CEvent *sync = (CEvent *)arg; ++ sync->Set(); ++} ++ ++void CRBP::WaitVsync() + { +- DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( 0 /*screen*/ ); +- DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); +- +- VC_DISPMANX_ALPHA_T alpha = { (DISPMANX_FLAGS_ALPHA_T)(DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS), 120, /*alpha 0->255*/ 0 }; +- VC_RECT_T src_rect; +- VC_RECT_T dst_rect; +- vc_dispmanx_rect_set( &src_rect, 0, 0, 1 << 16, 1 << 16 ); +- vc_dispmanx_rect_set( &dst_rect, 0, 0, 1, 1 ); +- +- if (m_element) +- vc_dispmanx_element_remove( update, m_element ); +- +- m_element = vc_dispmanx_element_add( update, +- display, +- 2000, // layer +- &dst_rect, +- m_resource, +- &src_rect, +- DISPMANX_PROTECTION_NONE, +- &alpha, +- NULL, // clamp +- (DISPMANX_TRANSFORM_T)0 ); +- +- vc_dispmanx_update_submit_sync(update); +- vc_dispmanx_display_close( display ); ++ int s; ++ CEvent sync; ++ DISPMANX_DISPLAY_HANDLE_T m_display = vc_dispmanx_display_open( 0 /*screen*/ ); ++ if (m_display == DISPMANX_NO_HANDLE) ++ { ++ CLog::Log(LOGDEBUG, "CRBP::%s skipping while display closed", __func__); ++ return; ++ } ++ s = vc_dispmanx_vsync_callback(m_display, vsync_callback, (void *)&sync); ++ if (s == 0) ++ { ++ sync.Wait(); ++ } ++ else assert(0); ++ s = vc_dispmanx_vsync_callback(m_display, NULL, NULL); ++ assert(s == 0); ++ vc_dispmanx_display_close( m_display ); + } + + +@@ -206,6 +212,9 @@ void CRBP::Deinitialize() + if(m_omx_initialized) + m_OMX->Deinitialize(); + ++ if (m_display) ++ CloseDisplay(m_display); ++ + m_DllBcmHost->bcm_host_deinit(); + + if(m_initialized) +diff --git a/xbmc/linux/RBP.h b/xbmc/linux/RBP.h +index f947acc..ca80045 100644 +--- a/xbmc/linux/RBP.h ++++ b/xbmc/linux/RBP.h +@@ -53,6 +53,8 @@ class CRBP + bool GetCodecMpg2() { return m_codec_mpg2_enabled; } + bool GetCodecWvc1() { return m_codec_wvc1_enabled; } + void GetDisplaySize(int &width, int &height); ++ DISPMANX_DISPLAY_HANDLE_T OpenDisplay(uint32_t device); ++ void CloseDisplay(DISPMANX_DISPLAY_HANDLE_T display); + int GetGUIResolutionLimit() { return m_gui_resolution_limit; } + // stride can be null for packed output + unsigned char *CaptureDisplay(int width, int height, int *stride, bool swap_red_blue, bool video_only = true); +@@ -73,10 +75,9 @@ class CRBP + bool m_codec_mpg2_enabled; + bool m_codec_wvc1_enabled; + COMXCore *m_OMX; +- DISPMANX_RESOURCE_HANDLE_T m_resource; +- DISPMANX_ELEMENT_HANDLE_T m_element; + class DllLibOMXCore; + CCriticalSection m_critSection; ++ DISPMANX_DISPLAY_HANDLE_T m_display; + }; + + extern CRBP g_RBP; +diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +index ca36082..4b74ea0 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp +@@ -306,7 +306,7 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res) + m_desktopRes = res; } - double dts_end() --- -2.0.4 - +- m_dispman_display = m_DllBcmHost->vc_dispmanx_display_open(0); ++ m_dispman_display = g_RBP.OpenDisplay(0); + + m_width = res.iWidth; + m_height = res.iHeight; +@@ -571,7 +571,7 @@ void CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow() + + if (m_dispman_display != DISPMANX_NO_HANDLE) + { +- m_DllBcmHost->vc_dispmanx_display_close(m_dispman_display); ++ g_RBP.CloseDisplay(m_dispman_display); + m_dispman_display = DISPMANX_NO_HANDLE; + } + DLOG("CEGLNativeTypeRaspberryPI::DestroyDispmaxWindow\n"); diff --git a/projects/RPi/xbmc/advancedsettings.xml b/projects/RPi/xbmc/advancedsettings.xml index 8ac95e3611..e1a7c0dc9b 100644 --- a/projects/RPi/xbmc/advancedsettings.xml +++ b/projects/RPi/xbmc/advancedsettings.xml @@ -6,15 +6,9 @@ 540 - - 20971520 - - 30