diff --git a/packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch b/packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch deleted file mode 100644 index 09bd995e17..0000000000 --- a/packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch +++ /dev/null @@ -1,2742 +0,0 @@ -From d1d19f8d0a69f751b03a97ef0f546564527a7caa Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 18:53:25 +0100 -Subject: [PATCH 01/18] [imx] @wolfgar Renamed CDVDVideoCodecIMXBuffer to - CDVDVideoCodecIMXVPUBuffer and added typedef for Renderer - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 34 +++++------ - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 70 +++++++++++----------- - 2 files changed, 53 insertions(+), 51 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 34db863..17d2f15 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -264,7 +264,7 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) - uvSize=Align(uvSize,nAlign); - } - -- m_outputBuffers = new CDVDVideoCodecIMXBuffer*[m_vpuFrameBufferNum]; -+ m_outputBuffers = new CDVDVideoCodecIMXVPUBuffer*[m_vpuFrameBufferNum]; - - for (int i=0 ; i < m_vpuFrameBufferNum; i++) - { -@@ -319,9 +319,9 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) - m_vpuFrameBuffers[i].pbufVirtCb_tilebot=0; - - #ifdef TRACE_FRAMES -- m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(i); -+ m_outputBuffers[i] = new CDVDVideoCodecIMXVPUBuffer(i); - #else -- m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(); -+ m_outputBuffers[i] = new CDVDVideoCodecIMXVPUBuffer(); - #endif - } - -@@ -916,7 +916,7 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) - int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); - if (idx != -1) - { -- CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; -+ CDVDVideoCodecIMXVPUBuffer *buffer = m_outputBuffers[idx]; - - pDvdVideoPicture->pts = buffer->GetPts(); - pDvdVideoPicture->dts = m_dts; -@@ -978,11 +978,11 @@ void CDVDVideoCodecIMX::Leave() - /*******************************************/ - - #ifdef TRACE_FRAMES --CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx) -+CDVDVideoCodecIMXVPUBuffer::CDVDVideoCodecIMXVPUBuffer(int idx) - : m_refs(1) - , m_idx(idx) - #else --CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() -+CDVDVideoCodecIMXVPUBuffer::CDVDVideoCodecIMXVPUBuffer() - : m_refs(1) - #endif - , m_frameBuffer(NULL) -@@ -992,7 +992,7 @@ CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() - { - } - --void CDVDVideoCodecIMXBuffer::Lock() -+void CDVDVideoCodecIMXVPUBuffer::Lock() - { - #ifdef TRACE_FRAMES - long count = AtomicIncrement(&m_refs); -@@ -1002,7 +1002,7 @@ void CDVDVideoCodecIMXBuffer::Lock() - #endif - } - --long CDVDVideoCodecIMXBuffer::Release() -+long CDVDVideoCodecIMXVPUBuffer::Release() - { - long count = AtomicDecrement(&m_refs); - #ifdef TRACE_FRAMES -@@ -1034,18 +1034,18 @@ long CDVDVideoCodecIMXBuffer::Release() - return count; - } - --bool CDVDVideoCodecIMXBuffer::IsValid() -+bool CDVDVideoCodecIMXVPUBuffer::IsValid() - { - return m_frameBuffer != NULL; - } - --bool CDVDVideoCodecIMXBuffer::Rendered() const -+bool CDVDVideoCodecIMXVPUBuffer::Rendered() const - { - return m_rendered; - } - --void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo, -- CDVDVideoCodecIMXBuffer *previous) -+void CDVDVideoCodecIMXVPUBuffer::Queue(VpuDecOutFrameInfo *frameInfo, -+ CDVDVideoCodecIMXVPUBuffer *previous) - { - // No lock necessary because at this time there is definitely no - // thread still holding a reference -@@ -1061,7 +1061,7 @@ void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo, - m_phyAddr = m_frameBuffer->pbufY; - } - --VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) -+VpuDecRetCode CDVDVideoCodecIMXVPUBuffer::ReleaseFramebuffer(VpuDecHandle *handle) - { - // Again no lock required because this is only issued after the last - // external reference was released -@@ -1084,22 +1084,22 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) - return ret; - } - --void CDVDVideoCodecIMXBuffer::SetPts(double pts) -+void CDVDVideoCodecIMXVPUBuffer::SetPts(double pts) - { - m_pts = pts; - } - --double CDVDVideoCodecIMXBuffer::GetPts(void) const -+double CDVDVideoCodecIMXVPUBuffer::GetPts(void) const - { - return m_pts; - } - --CDVDVideoCodecIMXBuffer *CDVDVideoCodecIMXBuffer::GetPreviousBuffer() const -+CDVDVideoCodecIMXVPUBuffer *CDVDVideoCodecIMXVPUBuffer::GetPreviousBuffer() const - { - return m_previousBuffer; - } - --CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() -+CDVDVideoCodecIMXVPUBuffer::~CDVDVideoCodecIMXVPUBuffer() - { - assert(m_refs == 0); - #ifdef TRACE_FRAMES -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 6533683..eb88ecd 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -48,13 +48,13 @@ class CDecMemInfo - VpuMemDesc* phyMem; - }; - --class CDVDVideoCodecIMXBuffer -+class CDVDVideoCodecIMXVPUBuffer - { - public: - #ifdef TRACE_FRAMES -- CDVDVideoCodecIMXBuffer(int idx); -+ CDVDVideoCodecIMXVPUBuffer(int idx); - #else -- CDVDVideoCodecIMXBuffer(); -+ CDVDVideoCodecIMXVPUBuffer(); - #endif - - // reference counting -@@ -64,11 +64,11 @@ class CDVDVideoCodecIMXBuffer - - bool Rendered() const; - void Queue(VpuDecOutFrameInfo *frameInfo, -- CDVDVideoCodecIMXBuffer *previous); -+ CDVDVideoCodecIMXVPUBuffer *previous); - VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); - void SetPts(double pts); - double GetPts(void) const; -- CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const; -+ CDVDVideoCodecIMXVPUBuffer *GetPreviousBuffer() const; - - uint32_t m_iWidth; - uint32_t m_iHeight; -@@ -77,7 +77,7 @@ class CDVDVideoCodecIMXBuffer - - private: - // private because we are reference counted -- virtual ~CDVDVideoCodecIMXBuffer(); -+ virtual ~CDVDVideoCodecIMXVPUBuffer(); - - private: - #ifdef TRACE_FRAMES -@@ -87,13 +87,15 @@ class CDVDVideoCodecIMXBuffer - VpuFrameBuffer *m_frameBuffer; - bool m_rendered; - double m_pts; -- CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds a the reference counted -+ CDVDVideoCodecIMXVPUBuffer *m_previousBuffer; // Holds a the reference counted - // previous buffer - }; - -+typedef CDVDVideoCodecIMXVPUBuffer CDVDVideoCodecIMXBuffer; -+ - class CDVDVideoCodecIMX : public CDVDVideoCodec - { -- friend class CDVDVideoCodecIMXBuffer; -+ friend class CDVDVideoCodecIMXVPUBuffer; - friend class CDVDVideoCodecIPUBuffer; - - public: -@@ -122,30 +124,30 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec - bool VpuAllocFrameBuffers(); - int VpuFindBuffer(void *frameAddr); - -- static const int m_extraVpuBuffers; // Number of additional buffers for VPU -- static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop -- static CCriticalSection m_codecBufferLock; // Lock to protect buffers handled -- // by both decoding and rendering threads -- -- CDVDStreamInfo m_hints; // Hints from demuxer at stream opening -- const char *m_pFormatName; // Current decoder format name -- VpuDecOpenParam m_decOpenParam; // Parameters required to call VPU_DecOpen -- CDecMemInfo m_decMemInfo; // VPU dedicated memory description -- VpuDecHandle m_vpuHandle; // Handle for VPU library calls -- VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start -- bool m_dropState; // Current drop state -- int m_vpuFrameBufferNum; // Total number of allocated frame buffers -- VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description -- CDVDVideoCodecIMXBuffer **m_outputBuffers; // Table of VPU output buffers -- CDVDVideoCodecIMXBuffer *m_lastBuffer; // Keep track of previous VPU output buffer (needed by deinterlacing motion engin) -- VpuMemDesc *m_extraMem; // Table of allocated extra Memory -- int m_frameCounter; // Decoded frames counter -- bool m_usePTS; // State whether pts out of decoding process should be used -- VpuDecOutFrameInfo m_frameInfo; // Store last VPU output frame info -- CBitstreamConverter *m_converter; // H264 annex B converter -- bool m_convert_bitstream; // State whether bitstream conversion is required -- int m_bytesToBeConsumed; // Remaining bytes in VPU -- double m_previousPts; // Enable to keep pts when needed -- bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu -- double m_dts; // Current dts -+ static const int m_extraVpuBuffers; // Number of additional buffers for VPU -+ static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop -+ static CCriticalSection m_codecBufferLock; // Lock to protect buffers handled -+ // by both decoding and rendering threads -+ -+ CDVDStreamInfo m_hints; // Hints from demuxer at stream opening -+ const char *m_pFormatName; // Current decoder format name -+ VpuDecOpenParam m_decOpenParam; // Parameters required to call VPU_DecOpen -+ CDecMemInfo m_decMemInfo; // VPU dedicated memory description -+ VpuDecHandle m_vpuHandle; // Handle for VPU library calls -+ VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start -+ bool m_dropState; // Current drop state -+ int m_vpuFrameBufferNum; // Total number of allocated frame buffers -+ VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description -+ CDVDVideoCodecIMXVPUBuffer **m_outputBuffers; // Table of VPU output buffers -+ CDVDVideoCodecIMXVPUBuffer *m_lastBuffer; // Keep track of previous VPU output buffer (needed by deinterlacing motion engin) -+ VpuMemDesc *m_extraMem; // Table of allocated extra Memory -+ int m_frameCounter; // Decoded frames counter -+ bool m_usePTS; // State whether pts out of decoding process should be used -+ VpuDecOutFrameInfo m_frameInfo; // Store last VPU output frame info -+ CBitstreamConverter *m_converter; // H264 annex B converter -+ bool m_convert_bitstream; // State whether bitstream conversion is required -+ int m_bytesToBeConsumed; // Remaining bytes in VPU -+ double m_previousPts; // Enable to keep pts when needed -+ bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu -+ double m_dts; // Current dts - }; - -From f62a4dab8e084dffa74fddfbc5cdc16a2b49f721 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 18:58:33 +0100 -Subject: [PATCH 02/18] [imx] @wolfgar Indentation - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 34 +++++++++++----------- - 1 file changed, 17 insertions(+), 17 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index eb88ecd..88b555c 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -58,16 +58,16 @@ class CDVDVideoCodecIMXVPUBuffer - #endif - - // reference counting -- virtual void Lock(); -- virtual long Release(); -- virtual bool IsValid(); -- -- bool Rendered() const; -- void Queue(VpuDecOutFrameInfo *frameInfo, -- CDVDVideoCodecIMXVPUBuffer *previous); -- VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); -- void SetPts(double pts); -- double GetPts(void) const; -+ virtual void Lock(); -+ virtual long Release(); -+ virtual bool IsValid(); -+ -+ bool Rendered() const; -+ void Queue(VpuDecOutFrameInfo *frameInfo, -+ CDVDVideoCodecIMXVPUBuffer *previous); -+ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); -+ void SetPts(double pts); -+ double GetPts(void) const; - CDVDVideoCodecIMXVPUBuffer *GetPreviousBuffer() const; - - uint32_t m_iWidth; -@@ -77,18 +77,18 @@ class CDVDVideoCodecIMXVPUBuffer - - private: - // private because we are reference counted -- virtual ~CDVDVideoCodecIMXVPUBuffer(); -+ virtual ~CDVDVideoCodecIMXVPUBuffer(); - - private: - #ifdef TRACE_FRAMES -- int m_idx; -+ int m_idx; - #endif -- long m_refs; -- VpuFrameBuffer *m_frameBuffer; -- bool m_rendered; -- double m_pts; -+ long m_refs; -+ VpuFrameBuffer *m_frameBuffer; -+ bool m_rendered; -+ double m_pts; - CDVDVideoCodecIMXVPUBuffer *m_previousBuffer; // Holds a the reference counted -- // previous buffer -+ // previous buffer - }; - - typedef CDVDVideoCodecIMXVPUBuffer CDVDVideoCodecIMXBuffer; - -From 7190879c7e4038e26edec13d50f026fed1d95728 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:04:49 +0100 -Subject: [PATCH 03/18] [imx] @wolfgar Added base class CDVDVideoCodecIMXBuffer - that CDVDVideoCodecIMXVPUBuffer derives from - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 8 ++-- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 40 ++++++++++------ - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 53 ++++++++++++++++------ - 3 files changed, 67 insertions(+), 34 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 81fe19b..b0229ef 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -2733,16 +2733,16 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) - glBindTexture(m_textureTarget, plane.id); - - GLuint physical = ~0U; -- GLvoid *virt = (GLvoid*)IMXBuffer->m_VirtAddr; -- glTexDirectVIVMap(m_textureTarget, IMXBuffer->m_iWidth, IMXBuffer->m_iHeight, GL_VIV_NV12, -+ GLvoid *virt = (GLvoid*)IMXBuffer->pVirtAddr; -+ glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_VIV_NV12, - (GLvoid **)&virt, &physical); - glTexDirectInvalidateVIV(m_textureTarget); - - glBindTexture(m_textureTarget, 0); - - plane.flipindex = m_buffers[index].flipindex; -- plane.texwidth = IMXBuffer->m_iWidth; -- plane.texheight = IMXBuffer->m_iHeight; -+ plane.texwidth = IMXBuffer->iWidth; -+ plane.texheight = IMXBuffer->iHeight; - - CalculateTextureSourceRects(index, 1); - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 17d2f15..9782a2c 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -976,18 +976,38 @@ void CDVDVideoCodecIMX::Leave() - } - - /*******************************************/ -+#ifdef TRACE_FRAMES -+CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx) -+ : m_idx(idx) -+ , m_refs(1) -+#else -+CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() -+ : m_refs(1) -+#endif -+ , m_pts(DVD_NOPTS_VALUE) -+ , m_dts(DVD_NOPTS_VALUE) -+{ -+} -+ -+void CDVDVideoCodecIMXBuffer::SetPts(double pts) -+{ -+ m_pts = pts; -+} -+ -+void CDVDVideoCodecIMXBuffer::SetDts(double dts) -+{ -+ m_dts = dts; -+} - - #ifdef TRACE_FRAMES - CDVDVideoCodecIMXVPUBuffer::CDVDVideoCodecIMXVPUBuffer(int idx) -- : m_refs(1) -- , m_idx(idx) -+ : CDVDVideoCodecIMXBuffer(idx) - #else - CDVDVideoCodecIMXVPUBuffer::CDVDVideoCodecIMXVPUBuffer() -- : m_refs(1) -+ : CDVDVideoCodecIMXBuffer() - #endif - , m_frameBuffer(NULL) - , m_rendered(false) -- , m_pts(DVD_NOPTS_VALUE) - , m_previousBuffer(NULL) - { - } -@@ -1078,22 +1098,12 @@ VpuDecRetCode CDVDVideoCodecIMXVPUBuffer::ReleaseFramebuffer(VpuDecHandle *handl - #endif - m_rendered = false; - m_frameBuffer = NULL; -- m_pts = DVD_NOPTS_VALUE; -+ SetPts(DVD_NOPTS_VALUE); - SAFE_RELEASE(m_previousBuffer); - - return ret; - } - --void CDVDVideoCodecIMXVPUBuffer::SetPts(double pts) --{ -- m_pts = pts; --} -- --double CDVDVideoCodecIMXVPUBuffer::GetPts(void) const --{ -- return m_pts; --} -- - CDVDVideoCodecIMXVPUBuffer *CDVDVideoCodecIMXVPUBuffer::GetPreviousBuffer() const - { - return m_previousBuffer; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 88b555c..c4452ca 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -48,7 +48,44 @@ class CDecMemInfo - VpuMemDesc* phyMem; - }; - --class CDVDVideoCodecIMXVPUBuffer -+// Base class of IMXVPU buffer -+class CDVDVideoCodecIMXBuffer { -+public: -+#ifdef TRACE_FRAMES -+ CDVDVideoCodecIMXBuffer(int idx); -+#else -+ CDVDVideoCodecIMXBuffer(); -+#endif -+ -+ // reference counting -+ virtual void Lock() = 0; -+ virtual long Release() = 0; -+ virtual bool IsValid() = 0; -+ -+ void SetPts(double pts); -+ double GetPts(void) const { return m_pts; } -+ -+ void SetDts(double dts); -+ double GetDts(void) const { return m_dts; } -+ -+ uint32_t iWidth; -+ uint32_t iHeight; -+ uint8_t *pPhysAddr; -+ uint8_t *pVirtAddr; -+ uint8_t iFormat; -+ -+protected: -+#ifdef TRACE_FRAMES -+ int m_idx; -+#endif -+ long m_refs; -+ -+private: -+ double m_pts; -+ double m_dts; -+}; -+ -+class CDVDVideoCodecIMXVPUBuffer : public CDVDVideoCodecIMXBuffer - { - public: - #ifdef TRACE_FRAMES -@@ -66,33 +103,19 @@ class CDVDVideoCodecIMXVPUBuffer - void Queue(VpuDecOutFrameInfo *frameInfo, - CDVDVideoCodecIMXVPUBuffer *previous); - VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); -- void SetPts(double pts); -- double GetPts(void) const; - CDVDVideoCodecIMXVPUBuffer *GetPreviousBuffer() const; - -- uint32_t m_iWidth; -- uint32_t m_iHeight; -- uint8_t *m_phyAddr; -- uint8_t *m_VirtAddr; -- - private: - // private because we are reference counted - virtual ~CDVDVideoCodecIMXVPUBuffer(); - - private: --#ifdef TRACE_FRAMES -- int m_idx; --#endif -- long m_refs; - VpuFrameBuffer *m_frameBuffer; - bool m_rendered; -- double m_pts; - CDVDVideoCodecIMXVPUBuffer *m_previousBuffer; // Holds a the reference counted - // previous buffer - }; - --typedef CDVDVideoCodecIMXVPUBuffer CDVDVideoCodecIMXBuffer; -- - class CDVDVideoCodecIMX : public CDVDVideoCodec - { - friend class CDVDVideoCodecIMXVPUBuffer; - -From fd94f1fcad232f4b8df20616ef2b4fe4fe84cd2c Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:15:04 +0100 -Subject: [PATCH 04/18] [imx] @wolfgar Added CDVDVideoCodecIMXIPUBuffer class - that wraps IPU allocated picture buffers - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 236 +++++++++++++++++++++ - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 44 +++- - 2 files changed, 279 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 9782a2c..e812b60 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -1116,3 +1116,239 @@ CDVDVideoCodecIMXVPUBuffer::~CDVDVideoCodecIMXVPUBuffer() - CLog::Log(LOGDEBUG, "~ %02d (VPU)\n", m_idx); - #endif - } -+ -+#ifdef TRACE_FRAMES -+CDVDVideoCodecIMXIPUBuffer::CDVDVideoCodecIMXIPUBuffer(int idx) -+ : CDVDVideoCodecIMXBuffer(idx) -+#else -+CDVDVideoCodecIMXIPUBuffer::CDVDVideoCodecIMXIPUBuffer() -+ : CDVDVideoCodecIMXBuffer() -+#endif -+ , m_bFree(true) -+ , m_pPhyAddr(0) -+ , m_pVirtAddr(NULL) -+ , m_nSize(0) -+{ -+} -+ -+CDVDVideoCodecIMXIPUBuffer::~CDVDVideoCodecIMXIPUBuffer() -+{ -+ assert(m_refs == 0); -+#ifdef TRACE_FRAMES -+ CLog::Log(LOGDEBUG, "~ %02d (IPU)\n", m_idx); -+#endif -+} -+ -+void CDVDVideoCodecIMXIPUBuffer::Lock() -+{ -+#ifdef TRACE_FRAMES -+ long count = AtomicIncrement(&m_refs); -+ CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (IPU)\n", m_idx, count); -+#else -+ AtomicIncrement(&m_refs); -+#endif -+ -+} -+ -+long CDVDVideoCodecIMXIPUBuffer::Release() -+{ -+ long count = AtomicDecrement(&m_refs); -+#ifdef TRACE_FRAMES -+ CLog::Log(LOGDEBUG, "R- %02d - ref : %d (IPU)\n", m_idx, count); -+#endif -+ if (count == 1) -+ { -+ ReleaseFrameBuffer(); -+ } -+ else if (count == 0) -+ { -+ delete this; -+ } -+ -+ return count; -+} -+ -+bool CDVDVideoCodecIMXIPUBuffer::IsValid() -+{ -+ return /*m_source && m_source->IsValid() && */m_pPhyAddr; -+} -+ -+bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buffer, -+ VpuFieldType fieldType, int fieldFmt, -+ bool lowMotion) -+{ -+ CDVDVideoCodecIMXVPUBuffer *previousBuffer; -+ struct ipu_task task; -+ memset(&task, 0, sizeof(task)); -+ task.priority = IPU_TASK_PRIORITY_HIGH; -+ -+ if (lowMotion) -+ previousBuffer = buffer->GetPreviousBuffer(); -+ else -+ previousBuffer = NULL; -+ -+ m_bFree = true; -+ iWidth = buffer->iWidth; -+ iHeight = buffer->iHeight; -+ -+ // Input is the VPU decoded frame -+ task.input.width = iWidth; -+ task.input.height = iHeight; -+#ifdef IMX_INPUT_FORMAT_I420 -+ task.input.format = IPU_PIX_FMT_YUV420P; -+#else -+ task.input.format = IPU_PIX_FMT_NV12; -+#endif -+ -+ // Output is our IPU buffer -+ task.output.width = iWidth; -+ task.output.height = iHeight; -+#ifdef IMX_OUTPUT_FORMAT_I420 -+ task.output.format = IPU_PIX_FMT_YUV420P; -+ format = 0; -+#else -+ task.output.format = IPU_PIX_FMT_NV12; -+ iFormat = 1; -+#endif -+ task.output.paddr = (int)pPhysAddr; -+ -+ // Fill current and next buffer address -+ if (lowMotion && previousBuffer && previousBuffer->IsValid()) -+ { -+ task.input.paddr = (int)previousBuffer->pPhysAddr; -+ task.input.paddr_n = (int)buffer->pPhysAddr; -+ task.input.deinterlace.motion = LOW_MOTION; -+ } -+ else -+ { -+ task.input.paddr = (int)buffer->pPhysAddr; -+ task.input.deinterlace.motion = HIGH_MOTION; -+ } -+ -+ task.input.deinterlace.enable = 1; -+ task.input.deinterlace.field_fmt = fieldFmt; -+ -+ switch (fieldType) -+ { -+ case VPU_FIELD_TOP: -+ case VPU_FIELD_TB: -+ task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_TOP; -+ break; -+ case VPU_FIELD_BOTTOM: -+ case VPU_FIELD_BT: -+ task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_BOTTOM; -+ break; -+ default: -+ break; -+ } -+ -+#ifdef IMX_PROFILE -+ unsigned int time = XbmcThreads::SystemClockMillis(); -+#endif -+ int ret = ioctl(fd, IPU_QUEUE_TASK, &task); -+#ifdef IMX_PROFILE -+ CLog::Log(LOGDEBUG, "DEINT: tm:%d\n", XbmcThreads::SystemClockMillis() - time); -+#endif -+ if (ret < 0) -+ { -+ CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno)); -+ return false; -+ } -+ -+ m_bFree = false; -+ buffer->Lock(); -+ -+ // Copy PTS -+ SetPts(buffer->GetPts()); -+ SetDts(buffer->GetDts()); -+ -+ buffer->Release(); -+ -+ return true; -+} -+ -+void CDVDVideoCodecIMXIPUBuffer::ReleaseFrameBuffer() -+{ -+#ifdef TRACE_FRAMES -+ CLog::Log(LOGDEBUG, "- %02d (IPU)\n", m_idx); -+#endif -+ m_bFree = true; -+} -+ -+bool CDVDVideoCodecIMXIPUBuffer::Allocate(int fd, int width, int height, int nAlign) -+{ -+ m_iWidth = Align(width,FRAME_ALIGN); -+ m_iHeight = Align(height,(2*FRAME_ALIGN)); -+ // I420 == 12 bpp -+ m_nSize = m_iWidth*m_iHeight*12/8; -+ m_pPhyAddr = m_nSize; -+ -+ pPhysAddr = pVirtAddr = NULL; -+ -+ int r = ioctl(fd, IPU_ALLOC, &m_pPhyAddr); -+ if (r < 0) -+ { -+ m_pPhyAddr = 0; -+ CLog::Log(LOGERROR, "ioctl IPU_ALLOC fail: disable deinterlacing: %s\n", strerror(errno)); -+ return false; -+ } -+ -+ CLog::Log(LOGNOTICE, "IPU: alloc %d bytes for frame of %dx%d at 0x%x\n", -+ m_nSize, m_iWidth, m_iHeight, m_pPhyAddr); -+ -+ m_pVirtAddr = (uint8_t*)mmap(0, m_nSize, PROT_READ | PROT_WRITE, MAP_SHARED, -+ fd, m_pPhyAddr); -+ if (!m_pVirtAddr) -+ { -+ CLog::Log(LOGERROR, "IPU mmap failed: disable deinterlacing: %s\n", strerror(errno)); -+ return false; -+ } -+ -+ if (nAlign>1) -+ { -+ pPhysAddr = (uint8_t*)Align(m_pPhyAddr, nAlign); -+ pVirtAddr = (uint8_t*)Align(m_pVirtAddr, nAlign); -+ } -+ else -+ { -+ pPhysAddr = (uint8_t*)m_pPhyAddr; -+ pVirtAddr = (uint8_t*)m_pVirtAddr; -+ } -+ -+ return true; -+} -+ -+bool CDVDVideoCodecIMXIPUBuffer::Free(int fd) -+{ -+ bool ret = true; -+ -+ // Unmap virtual memory -+ if (m_pVirtAddr != NULL) -+ { -+ if(munmap(m_pVirtAddr, m_nSize)) -+ { -+ CLog::Log(LOGERROR, "IPU unmap failed: %s\n", strerror(errno)); -+ ret = false; -+ } -+ -+ m_pVirtAddr = NULL; -+ } -+ -+ // Free IPU memory -+ if (m_pPhyAddr) -+ { -+ if (ioctl(fd, IPU_FREE, &m_pPhyAddr)) -+ { -+ CLog::Log(LOGERROR, "IPU free buffer 0x%x failed: %s\n", -+ m_pPhyAddr, strerror(errno)); -+ ret = false; -+ } -+ -+ m_pPhyAddr = 0; -+ } -+ -+ pPhysAddr = pVirtAddr = NULL; -+ m_bFree = true; -+ -+ return ret; -+} -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index c4452ca..86edaa2 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -48,7 +48,8 @@ class CDecMemInfo - VpuMemDesc* phyMem; - }; - --// Base class of IMXVPU buffer -+ -+// Base class of IMXVPU and IMXIPU buffer - class CDVDVideoCodecIMXBuffer { - public: - #ifdef TRACE_FRAMES -@@ -85,6 +86,7 @@ class CDVDVideoCodecIMXBuffer { - double m_dts; - }; - -+ - class CDVDVideoCodecIMXVPUBuffer : public CDVDVideoCodecIMXBuffer - { - public: -@@ -116,6 +118,46 @@ class CDVDVideoCodecIMXVPUBuffer : public CDVDVideoCodecIMXBuffer - // previous buffer - }; - -+ -+// Shared buffer that holds an IPU allocated memory block and serves as target -+// for IPU operations such as deinterlacing, rotation or color conversion. -+class CDVDVideoCodecIMXIPUBuffer : public CDVDVideoCodecIMXBuffer -+{ -+public: -+#ifdef TRACE_FRAMES -+ CDVDVideoCodecIMXIPUBuffer(int idx); -+#else -+ CDVDVideoCodecIMXIPUBuffer(); -+#endif -+ -+ // reference counting -+ virtual void Lock(); -+ virtual long Release(); -+ virtual bool IsValid(); -+ -+ // Returns whether the buffer is ready to be used -+ bool Rendered() const { return m_bFree; } -+ bool Process(int fd, CDVDVideoCodecIMXVPUBuffer *buffer, -+ VpuFieldType fieldType, int fieldFmt, -+ bool lowMotion); -+ void ReleaseFrameBuffer(); -+ -+ bool Allocate(int fd, int width, int height, int nAlign); -+ bool Free(int fd); -+ -+private: -+ virtual ~CDVDVideoCodecIMXIPUBuffer(); -+ -+private: -+ bool m_bFree; -+ int m_pPhyAddr; -+ uint8_t *m_pVirtAddr; -+ uint32_t m_iWidth; -+ uint32_t m_iHeight; -+ int m_nSize; -+}; -+ -+ - class CDVDVideoCodecIMX : public CDVDVideoCodec - { - friend class CDVDVideoCodecIMXVPUBuffer; - -From 8c4eb96c7c82b66bad008dd521429f8cc1039d2d Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:16:49 +0100 -Subject: [PATCH 05/18] [imx] @wolfgar Added CDVDVideoCodecIMXIPUBuffers that - manages a pool of IPU buffers and implements deinterlacing of VPU buffers to - IPU buffers - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 134 +++++++++++++++++++++ - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 37 ++++++ - 2 files changed, 171 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index e812b60..5dfa4f8 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -1352,3 +1352,137 @@ bool CDVDVideoCodecIMXIPUBuffer::Free(int fd) - - return ret; - } -+ -+CDVDVideoCodecIMXIPUBuffers::CDVDVideoCodecIMXIPUBuffers() -+ : m_ipuHandle(0) -+ , m_bufferNum(0) -+ , m_buffers(NULL) -+ , m_currentFieldFmt(0) -+{ -+} -+ -+CDVDVideoCodecIMXIPUBuffers::~CDVDVideoCodecIMXIPUBuffers() -+{ -+ Close(); -+} -+ -+bool CDVDVideoCodecIMXIPUBuffers::Init(int width, int height, int numBuffers, int nAlign) -+{ -+ if (numBuffers<=0) -+ { -+ CLog::Log(LOGERROR, "IPU Init: invalid number of buffers: %d\n", numBuffers); -+ return false; -+ } -+ -+ m_ipuHandle = open("/dev/mxc_ipu", O_RDWR, 0); -+ if (m_ipuHandle<=0) -+ { -+ CLog::Log(LOGWARNING, "Failed to initialize IPU: deinterlacing disabled: %s\n", -+ strerror(errno)); -+ m_ipuHandle = 0; -+ return false; -+ } -+ -+ m_bufferNum = numBuffers; -+ m_buffers = new CDVDVideoCodecIMXIPUBuffer*[m_bufferNum]; -+ m_currentFieldFmt = 0; -+ -+ for (int i=0; i < m_bufferNum; i++) -+ { -+#ifdef TRACE_FRAMES -+ m_buffers[i] = new CDVDVideoCodecIMXIPUBuffer(i); -+#else -+ m_buffers[i] = new CDVDVideoCodecIMXIPUBuffer; -+#endif -+ if (!m_buffers[i]->Allocate(m_ipuHandle, width, height, nAlign)) -+ { -+ Close(); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+bool CDVDVideoCodecIMXIPUBuffers::Reset() -+{ -+ for (int i=0; i < m_bufferNum; i++) -+ m_buffers[i]->ReleaseFrameBuffer(); -+ m_currentFieldFmt = 0; -+} -+ -+bool CDVDVideoCodecIMXIPUBuffers::Close() -+{ -+ bool ret = true; -+ -+ if (m_ipuHandle) -+ { -+ for (int i=0; i < m_bufferNum; i++) -+ { -+ if (m_buffers[i] == NULL ) continue; -+ if (!m_buffers[i]->Free(m_ipuHandle)) -+ ret = false; -+ } -+ -+ // Close IPU device -+ if (close(m_ipuHandle)) -+ { -+ CLog::Log(LOGERROR, "IPU failed to close interface: %s\n", strerror(errno)); -+ ret = false; -+ } -+ -+ m_ipuHandle = 0; -+ } -+ -+ if (m_buffers) -+ { -+ for (int i=0; i < m_bufferNum; i++) -+ SAFE_RELEASE(m_buffers[i]); -+ -+ delete m_buffers; -+ m_buffers = NULL; -+ } -+ -+ m_bufferNum = 0; -+ return true; -+} -+ -+CDVDVideoCodecIMXIPUBuffer * -+CDVDVideoCodecIMXIPUBuffers::Process(CDVDVideoCodecIMXBuffer *sourceBuffer, -+ VpuFieldType fieldType, bool lowMotion) -+{ -+ CDVDVideoCodecIMXIPUBuffer *target = NULL; -+ bool ret = true; -+ -+ if (!m_bufferNum) -+ return NULL; -+ -+ for (int i=0; i < m_bufferNum; i++ ) -+ { -+ if (!m_buffers[i]->Rendered()) continue; -+ -+ // IPU process: -+ // SRC: Current VPU physical buffer address + last VPU buffer address -+ // DST: IPU buffer[i] -+ ret = m_buffers[i]->Process(m_ipuHandle, (CDVDVideoCodecIMXVPUBuffer*)sourceBuffer, -+ fieldType, m_currentFieldFmt, -+ lowMotion); -+ if (ret) -+ { -+#ifdef TRACE_FRAMES -+ CLog::Log(LOGDEBUG, "+ %02d (IPU)\n", i); -+#endif -+ target = m_buffers[i]; -+ } -+ break; -+ } -+ -+ // Buffers are there but there is no free one, this is an error! -+ // Rendering will continue with unprocessed frames ... -+ if (ret && target==NULL) -+ { -+ CLog::Log(LOGERROR, "Deinterlacing: did not find free buffer, forward unprocessed frame\n"); -+ } -+ -+ return target; -+} -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 86edaa2..bb2f7d1 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -26,6 +26,14 @@ - #include "utils/BitstreamConverter.h" - - -+// The decoding format of the VPU buffer. Comment this to decode -+// as NV12. The VPU works faster with I420. -+#define IMX_INPUT_FORMAT_I420 -+ -+// The deinterlacer output and render format. Uncomment to use I420. -+// The IPU works faster when outputting to NV12. -+//#define IMX_OUTPUT_FORMAT_I420 -+ - //#define IMX_PROFILE - //#define TRACE_FRAMES - -@@ -158,6 +166,35 @@ class CDVDVideoCodecIMXIPUBuffer : public CDVDVideoCodecIMXBuffer - }; - - -+// Collection class that manages a pool of IPU buffers that are used for -+// deinterlacing. In future they can also serve rotation or color conversion -+// buffers. -+class CDVDVideoCodecIMXIPUBuffers -+{ -+ public: -+ CDVDVideoCodecIMXIPUBuffers(); -+ ~CDVDVideoCodecIMXIPUBuffers(); -+ -+ bool Init(int width, int height, int numBuffers, int nAlign); -+ // Sets the mode to be used if deinterlacing is set to AUTO -+ void SetAutoMode(bool mode) { m_autoMode = mode; } -+ bool AutoMode() const { return m_autoMode; } -+ bool Reset(); -+ bool Close(); -+ -+ CDVDVideoCodecIMXIPUBuffer * -+ Process(CDVDVideoCodecIMXBuffer *sourceBuffer, -+ VpuFieldType fieldType, bool lowMotion); -+ -+ private: -+ int m_ipuHandle; -+ bool m_autoMode; -+ int m_bufferNum; -+ CDVDVideoCodecIMXIPUBuffer **m_buffers; -+ int m_currentFieldFmt; -+}; -+ -+ - class CDVDVideoCodecIMX : public CDVDVideoCodec - { - friend class CDVDVideoCodecIMXVPUBuffer; - -From 4b14e49ad629c7fe22b438aee2065dafd426c97f Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:22:28 +0100 -Subject: [PATCH 06/18] [imx] @wolfgar Added mixer thread implementation with - capacity limited input/output queue - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 248 ++++++++++++++++++++- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 90 ++++++++ - 2 files changed, 336 insertions(+), 2 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 5dfa4f8..6da91eb 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -26,11 +26,15 @@ - #include - #include - #include -+#include -+#include -+#include "settings/MediaSettings.h" -+#include "settings/VideoSettings.h" -+#include "settings/AdvancedSettings.h" - #include "threads/SingleLock.h" -+#include "threads/Atomics.h" - #include "utils/log.h" - #include "DVDClock.h" --#include "settings/AdvancedSettings.h" --#include "threads/Atomics.h" - - #define FRAME_ALIGN 16 - #define MEDIAINFO 1 -@@ -1486,3 +1490,243 @@ CDVDVideoCodecIMXIPUBuffers::Process(CDVDVideoCodecIMXBuffer *sourceBuffer, - - return target; - } -+ -+ -+CDVDVideoMixerIMX::CDVDVideoMixerIMX(CDVDVideoCodecIMXIPUBuffers *proc) -+ : CThread("IMX6 Mixer") -+ , m_beginInput(0), m_endInput(0), m_bufferedInput(0) -+ , m_beginOutput(0), m_endOutput(0), m_bufferedOutput(0) -+ , m_proc(proc) -+{ -+} -+ -+CDVDVideoMixerIMX::~CDVDVideoMixerIMX() -+{ -+ Dispose(); -+} -+ -+void CDVDVideoMixerIMX::SetCapacity(int nInput, int nOutput) -+{ -+ Reset(); -+ m_input.resize(nInput); -+ m_output.resize(nOutput); -+} -+ -+void CDVDVideoMixerIMX::Start() -+{ -+ Create(); -+} -+ -+void CDVDVideoMixerIMX::Reset() -+{ -+ CSingleLock lk(m_monitor); -+ -+ // Release all still referenced buffers -+ for (size_t i = 0; i < m_input.size(); ++i) -+ { -+ SAFE_RELEASE(m_input[i]); -+ m_input[i] = NULL; -+ } -+ -+ for (size_t i = 0; i < m_output.size(); ++i) -+ { -+ SAFE_RELEASE(m_output[i]); -+ m_output[i] = NULL; -+ } -+ -+ // Reset ring buffer -+ m_beginInput = m_endInput = m_bufferedInput = 0; -+ m_beginOutput = m_endOutput = m_bufferedOutput = 0; -+ -+ m_inputNotFull.notifyAll(); -+ m_outputNotFull.notifyAll(); -+} -+ -+void CDVDVideoMixerIMX::Dispose() -+{ -+ StopThread(); -+ Reset(); -+} -+ -+bool CDVDVideoMixerIMX::IsActive() { -+ return IsRunning(); -+} -+ -+CDVDVideoCodecIMXBuffer *CDVDVideoMixerIMX::Process(CDVDVideoCodecIMXVPUBuffer *buffer) -+{ -+ CSingleLock lk(m_monitor); -+ CDVDVideoCodecIMXBuffer *r; -+ -+ if (m_bStop) -+ { -+ m_inputNotEmpty.notifyAll(); -+ m_outputNotFull.notifyAll(); -+ SAFE_RELEASE(buffer); -+ return NULL; -+ } -+ -+ if (m_bufferedOutput) -+ { -+ // Pop the output -+ r = m_output[m_beginOutput]; -+ m_output[m_beginOutput] = NULL; -+ m_beginOutput = (m_beginOutput+1) % m_output.size(); -+ --m_bufferedOutput; -+ m_outputNotFull.notifyAll(); -+ } -+ else -+ r = NULL; -+ -+ // Flush call? -+ if (!buffer) -+ return r; -+ -+ // If the input queue is full, wait for a free slot -+ while ((m_bufferedInput == m_input.size()) && !m_bStop) -+ m_inputNotFull.wait(lk); -+ -+ if (m_bStop) -+ { -+ m_inputNotEmpty.notifyAll(); -+ m_outputNotFull.notifyAll(); -+ buffer->Release(); -+ return r; -+ } -+ -+ // Store the value -+ m_input[m_endInput] = buffer; -+ m_endInput = (m_endInput+1) % m_input.size(); -+ ++m_bufferedInput; -+ m_inputNotEmpty.notifyAll(); -+ -+ //CLog::Log(LOGNOTICE, "Pushed input frame %x\n", (int)buffer); -+ -+ return r; -+} -+ -+void CDVDVideoMixerIMX::OnStartup() -+{ -+ CLog::Log(LOGNOTICE, "CDVDVideoMixerIMX::OnStartup: Mixer Thread created"); -+} -+ -+void CDVDVideoMixerIMX::OnExit() -+{ -+ CLog::Log(LOGNOTICE, "CDVDVideoMixerIMX::OnExit: Mixer Thread terminated"); -+} -+ -+void CDVDVideoMixerIMX::StopThread(bool bWait /*= true*/) -+{ -+ CThread::StopThread(false); -+ m_inputNotFull.notifyAll(); -+ m_inputNotEmpty.notifyAll(); -+ m_outputNotFull.notifyAll(); -+ if (bWait) -+ CThread::StopThread(true); -+} -+ -+void CDVDVideoMixerIMX::Process() -+{ -+ while (!m_bStop) -+ { -+ // Blocking until an input is available -+ CDVDVideoCodecIMXVPUBuffer *inputBuffer = GetNextInput(); -+ if (inputBuffer) -+ { -+ // Wait for free slot -+ WaitForFreeOutput(); -+ -+ CDVDVideoCodecIMXBuffer *outputBuffer = ProcessFrame(inputBuffer); -+ -+ // Queue the output if any -+ if (outputBuffer) -+ { -+ // Blocking until a free output slot is available. The buffer is -+ // reference counted in PushOutput -+ PushOutput(outputBuffer); -+ } -+ -+ SAFE_RELEASE(inputBuffer); -+ } -+ } -+} -+ -+CDVDVideoCodecIMXVPUBuffer *CDVDVideoMixerIMX::GetNextInput() { -+ CSingleLock lk(m_monitor); -+ while (!m_bufferedInput && !m_bStop) -+ m_inputNotEmpty.wait(lk); -+ -+ if (m_bStop) -+ return NULL; -+ -+ CDVDVideoCodecIMXVPUBuffer *v = m_input[m_beginInput]; -+ m_input[m_beginInput] = NULL; -+ m_beginInput = (m_beginInput+1) % m_input.size(); -+ --m_bufferedInput; -+ m_inputNotFull.notifyAll(); -+ -+ //CLog::Log(LOGNOTICE, "Popped input frame %x\n", (int)v); -+ -+ return v; -+} -+ -+void CDVDVideoMixerIMX::WaitForFreeOutput() { -+ CSingleLock lk(m_monitor); -+ -+ // Output queue is full, wait for a free slot -+ while (m_bufferedOutput == m_output.size() && !m_bStop) -+ m_outputNotFull.wait(lk); -+} -+ -+bool CDVDVideoMixerIMX::PushOutput(CDVDVideoCodecIMXBuffer *v) { -+ CSingleLock lk(m_monitor); -+ -+ v->Lock(); -+ -+ // If closed return false -+ if (m_bStop) -+ { -+ v->Release(); -+ return false; -+ } -+ -+ // Store the value -+ m_output[m_endOutput] = v; -+ m_endOutput = (m_endOutput+1) % m_output.size(); -+ ++m_bufferedOutput; -+ -+ return true; -+} -+ -+CDVDVideoCodecIMXBuffer *CDVDVideoMixerIMX::ProcessFrame(CDVDVideoCodecIMXVPUBuffer *inputBuffer) -+{ -+ CDVDVideoCodecIMXBuffer *outputBuffer; -+ EDEINTERLACEMODE mDeintMode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; -+ //EINTERLACEMETHOD mInt = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; -+ -+ if ((mDeintMode == VS_DEINTERLACEMODE_OFF) -+ || ((mDeintMode == VS_DEINTERLACEMODE_AUTO) && !m_proc->AutoMode())) -+ { -+ outputBuffer = inputBuffer; -+ } -+ else -+ { -+#ifdef IMX_PROFILE_BUFFERS -+ unsigned long long current = XbmcThreads::SystemClockMillis(); -+#endif -+//#define DUMMY_DEINTERLACER -+#ifdef DUMMY_DEINTERLACER -+ Sleep(35); -+ outputBuffer = inputBuffer; -+#else -+ outputBuffer = m_proc->Process(inputBuffer, -+ inputBuffer->GetFieldType(), -+ false); -+#endif -+#ifdef IMX_PROFILE_BUFFERS -+ CLog::Log(LOGNOTICE, "+P %x %lld\n", (int)outputBuffer, -+ XbmcThreads::SystemClockMillis()-current); -+#endif -+ } -+ -+ return outputBuffer; -+} -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index bb2f7d1..5b4d835 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -19,10 +19,14 @@ - * - */ - #include -+#include - #include - #include "DVDVideoCodec.h" - #include "DVDStreamInfo.h" - #include "threads/CriticalSection.h" -+#include "threads/Condition.h" -+#include "threads/Event.h" -+#include "threads/Thread.h" - #include "utils/BitstreamConverter.h" - - -@@ -34,6 +38,15 @@ - // The IPU works faster when outputting to NV12. - //#define IMX_OUTPUT_FORMAT_I420 - -+// This enables logging of times for Decode->Decode, Render->Render, -+// Deinterlace->Deinterlace. It helps to profile several stages of -+// processing with respect to changed kernels or other configurations. -+// Since we utilize VPU, IPU and GPU at the same time different kernel -+// priorities to those subsystems can result in a very different user -+// experience. With that setting enabled we can build some statistics, -+// as numbers are always better than "feelings" -+//#define IMX_PROFILE_BUFFERS -+ - //#define IMX_PROFILE - //#define TRACE_FRAMES - -@@ -195,6 +208,83 @@ class CDVDVideoCodecIMXIPUBuffers - }; - - -+// Collection class that manages a pool of IPU buffers that are used for -+// deinterlacing. In future they can also serve rotation or color conversion -+// buffers. -+class CDVDVideoCodecIMXIPUBuffers -+{ -+ public: -+ CDVDVideoCodecIMXIPUBuffers(); -+ ~CDVDVideoCodecIMXIPUBuffers(); -+ -+ bool Init(int width, int height, int numBuffers, int nAlign); -+ // Sets the mode to be used if deinterlacing is set to AUTO -+ void SetAutoMode(bool mode) { m_autoMode = mode; } -+ bool AutoMode() const { return m_autoMode; } -+ bool Reset(); -+ bool Close(); -+ -+ CDVDVideoCodecIMXIPUBuffer * -+ Process(CDVDVideoCodecIMXBuffer *sourceBuffer, -+ VpuFieldType fieldType, bool lowMotion); -+ -+ private: -+ int m_ipuHandle; -+ bool m_autoMode; -+ int m_bufferNum; -+ CDVDVideoCodecIMXIPUBuffer **m_buffers; -+ int m_currentFieldFmt; -+}; -+ -+ -+class CDVDVideoMixerIMX : private CThread { -+public: -+ CDVDVideoMixerIMX(CDVDVideoCodecIMXIPUBuffers *proc); -+ virtual ~CDVDVideoMixerIMX(); -+ -+ void SetCapacity(int intput, int output); -+ -+ void Start(); -+ void Reset(); -+ void Dispose(); -+ bool IsActive(); -+ -+ // This function blocks until an input slot is available. -+ // It returns if an output is available. -+ CDVDVideoCodecIMXBuffer *Process(CDVDVideoCodecIMXVPUBuffer *input); -+ -+private: -+ CDVDVideoCodecIMXVPUBuffer *GetNextInput(); -+ void WaitForFreeOutput(); -+ bool PushOutput(CDVDVideoCodecIMXBuffer *v); -+ CDVDVideoCodecIMXBuffer *ProcessFrame(CDVDVideoCodecIMXVPUBuffer *input); -+ -+ virtual void OnStartup(); -+ virtual void OnExit(); -+ virtual void StopThread(bool bWait = true); -+ virtual void Process(); -+ -+private: -+ typedef std::vector InputBuffers; -+ typedef std::vector OutputBuffers; -+ -+ CDVDVideoCodecIMXIPUBuffers *m_proc; -+ InputBuffers m_input; -+ volatile int m_beginInput, m_endInput; -+ volatile size_t m_bufferedInput; -+ XbmcThreads::ConditionVariable m_inputNotEmpty; -+ XbmcThreads::ConditionVariable m_inputNotFull; -+ -+ OutputBuffers m_output; -+ volatile int m_beginOutput, m_endOutput; -+ volatile size_t m_bufferedOutput; -+ XbmcThreads::ConditionVariable m_outputNotFull; -+ -+ mutable CCriticalSection m_monitor; -+ CDVDVideoCodecIMXBuffer *m_lastFrame; // Last input frame -+}; -+ -+ - class CDVDVideoCodecIMX : public CDVDVideoCodec - { - friend class CDVDVideoCodecIMXVPUBuffer; - -From 657ea2836b26cc70c3ed4cee881b876080ab228b Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:30:30 +0100 -Subject: [PATCH 07/18] [imx] @wolfgar Removed friend declaration - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 5b4d835..33e449f 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -287,9 +287,6 @@ class CDVDVideoMixerIMX : private CThread { - - class CDVDVideoCodecIMX : public CDVDVideoCodec - { -- friend class CDVDVideoCodecIMXVPUBuffer; -- friend class CDVDVideoCodecIPUBuffer; -- - public: - CDVDVideoCodecIMX(); - virtual ~CDVDVideoCodecIMX(); - -From 288033e49346e9f2710d1a145abadf2308553d54 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:42:49 +0100 -Subject: [PATCH 08/18] [imx] @wolfgar Added missing attribute to - CDVDVideoCodecIMXVPUBuffer, cosmetics (indentation) and allocate buffer - according to input format at compile time - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 130 ++++++++++++++------- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 7 +- - 2 files changed, 91 insertions(+), 46 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 6da91eb..87a6c48 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -94,8 +94,8 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) - return true; - - AllocFailure: -- VpuFreeBuffers(); -- return false; -+ VpuFreeBuffers(); -+ return false; - } - - int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr) -@@ -231,50 +231,76 @@ bool CDVDVideoCodecIMX::VpuOpen(void) - - bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) - { -+ int totalSize = 0; -+ int ySize = 0; -+ int uSize = 0; -+ int vSize = 0; -+ int mvSize = 0; -+ int yStride = 0; -+ int uvStride = 0; -+ - VpuDecRetCode ret; - VpuMemDesc vpuMem; -- int totalSize=0; -- int mvSize=0; -- int ySize=0; -- int uvSize=0; -- int yStride=0; -- int uvStride=0; - unsigned char* ptr; - unsigned char* ptrVirt; - int nAlign; - -- m_vpuFrameBufferNum = m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers; -+ m_vpuFrameBufferNum = m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers; - m_vpuFrameBuffers = new VpuFrameBuffer[m_vpuFrameBufferNum]; - -- yStride=Align(m_initInfo.nPicWidth,FRAME_ALIGN); -+ yStride = Align(m_initInfo.nPicWidth,FRAME_ALIGN); - if(m_initInfo.nInterlace) - { -- ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,(2*FRAME_ALIGN)); -+ ySize = Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,(2*FRAME_ALIGN)); - } - else - { -- ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN); -+ ySize = Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN); -+ } -+ -+#ifdef IMX_INPUT_FORMAT_I420 -+ switch (m_initInfo.nMjpgSourceFormat) -+ { -+ case 0: // I420 (4:2:0) -+ uvStride = yStride / 2; -+ uSize = vSize = mvSize = ySize / 4; -+ break; -+ case 1: // Y42B (4:2:2 horizontal) -+ uvStride = yStride / 2; -+ uSize = vSize = mvSize = ySize / 2; -+ break; -+ case 3: // Y444 (4:4:4) -+ uvStride = yStride; -+ uSize = vSize = mvSize = ySize; -+ break; -+ default: -+ CLog::Log(LOGERROR, "%s: invalid source format in init info\n",__FUNCTION__,ret); -+ return false; - } - -- //NV12 for all video -- uvStride=yStride; -- uvSize=ySize/2; -- mvSize=uvSize/2; -+#else -+ // NV12 -+ uvStride = yStride; -+ uSize = ySize/2; -+ mvSize = uSize/2; -+#endif - -- nAlign=m_initInfo.nAddressAlignment; -+ nAlign = m_initInfo.nAddressAlignment; - if(nAlign>1) - { -- ySize=Align(ySize,nAlign); -- uvSize=Align(uvSize,nAlign); -+ ySize = Align(ySize, nAlign); -+ uSize = Align(uSize, nAlign); -+ vSize = Align(vSize, nAlign); -+ mvSize = Align(mvSize, nAlign); - } - - m_outputBuffers = new CDVDVideoCodecIMXVPUBuffer*[m_vpuFrameBufferNum]; - - for (int i=0 ; i < m_vpuFrameBufferNum; i++) - { -- totalSize=(ySize+uvSize+mvSize+nAlign)*1; -+ totalSize = ySize + uSize + vSize + mvSize + nAlign; - -- vpuMem.nSize=totalSize; -+ vpuMem.nSize = totalSize; - ret = VPU_DecGetMem(&vpuMem); - if(ret != VPU_DEC_RET_SUCCESS) - { -@@ -291,36 +317,44 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) - m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nSize = vpuMem.nSize; - - //fill frameBuf -- ptr=(unsigned char*)vpuMem.nPhyAddr; -- ptrVirt=(unsigned char*)vpuMem.nVirtAddr; -+ ptr = (unsigned char*)vpuMem.nPhyAddr; -+ ptrVirt = (unsigned char*)vpuMem.nVirtAddr; - - //align the base address - if(nAlign>1) - { -- ptr=(unsigned char*)Align(ptr,nAlign); -- ptrVirt=(unsigned char*)Align(ptrVirt,nAlign); -+ ptr = (unsigned char*)Align(ptr,nAlign); -+ ptrVirt = (unsigned char*)Align(ptrVirt,nAlign); - } - - // fill stride info -- m_vpuFrameBuffers[i].nStrideY=yStride; -- m_vpuFrameBuffers[i].nStrideC=uvStride; -+ m_vpuFrameBuffers[i].nStrideY = yStride; -+ m_vpuFrameBuffers[i].nStrideC = uvStride; - - // fill phy addr -- m_vpuFrameBuffers[i].pbufY=ptr; -- m_vpuFrameBuffers[i].pbufCb=ptr+ySize; -- m_vpuFrameBuffers[i].pbufCr=0; -- m_vpuFrameBuffers[i].pbufMvCol=ptr+ySize+uvSize; -+ m_vpuFrameBuffers[i].pbufY = ptr; -+ m_vpuFrameBuffers[i].pbufCb = ptr + ySize; -+#ifdef IMX_INPUT_FORMAT_I420 -+ m_vpuFrameBuffers[i].pbufCr = ptr + ySize + uSize; -+#else -+ m_vpuFrameBuffers[i].pbufCr = 0; -+#endif -+ m_vpuFrameBuffers[i].pbufMvCol = ptr + ySize + uSize + vSize; - - // fill virt addr -- m_vpuFrameBuffers[i].pbufVirtY=ptrVirt; -- m_vpuFrameBuffers[i].pbufVirtCb=ptrVirt+ySize; -- m_vpuFrameBuffers[i].pbufVirtCr=0; -- m_vpuFrameBuffers[i].pbufVirtMvCol=ptrVirt+ySize+uvSize; -+ m_vpuFrameBuffers[i].pbufVirtY = ptrVirt; -+ m_vpuFrameBuffers[i].pbufVirtCb = ptrVirt + ySize; -+#ifdef IMX_INPUT_FORMAT_I420 -+ m_vpuFrameBuffers[i].pbufVirtCr = ptrVirt + ySize + uSize; -+#else -+ m_vpuFrameBuffers[i].pbufVirtCr = 0; -+#endif -+ m_vpuFrameBuffers[i].pbufVirtMvCol = ptrVirt + ySize + uSize + vSize; - -- m_vpuFrameBuffers[i].pbufY_tilebot=0; -- m_vpuFrameBuffers[i].pbufCb_tilebot=0; -- m_vpuFrameBuffers[i].pbufVirtY_tilebot=0; -- m_vpuFrameBuffers[i].pbufVirtCb_tilebot=0; -+ m_vpuFrameBuffers[i].pbufY_tilebot = 0; -+ m_vpuFrameBuffers[i].pbufCb_tilebot = 0; -+ m_vpuFrameBuffers[i].pbufVirtY_tilebot = 0; -+ m_vpuFrameBuffers[i].pbufVirtCb_tilebot = 0; - - #ifdef TRACE_FRAMES - m_outputBuffers[i] = new CDVDVideoCodecIMXVPUBuffer(i); -@@ -647,7 +681,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) - m_bytesToBeConsumed += inData.nSize; - ret = VPU_DecDecodeBuf(m_vpuHandle, &inData, &decRet); - #ifdef IMX_PROFILE -- CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, XbmcThreads::SystemClockMillis() - before_dec); -+ CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, XbmcThreads::SystemClockMillis() - before_dec); - #endif - - if (ret != VPU_DEC_RET_SUCCESS) -@@ -1079,10 +1113,18 @@ void CDVDVideoCodecIMXVPUBuffer::Queue(VpuDecOutFrameInfo *frameInfo, - if (m_previousBuffer) - m_previousBuffer->Lock(); - -- m_iWidth = frameInfo->pExtInfo->nFrmWidth; -- m_iHeight = frameInfo->pExtInfo->nFrmHeight; -- m_VirtAddr = m_frameBuffer->pbufVirtY; -- m_phyAddr = m_frameBuffer->pbufY; -+ iWidth = frameInfo->pExtInfo->nFrmWidth; -+ iHeight = frameInfo->pExtInfo->nFrmHeight; -+ pVirtAddr = m_frameBuffer->pbufVirtY; -+ pPhysAddr = m_frameBuffer->pbufY; -+ -+ m_fieldType = frameInfo->eFieldType; -+ // We decode to I420 -+#ifdef IMX_INPUT_FORMAT_I420 -+ iFormat = 0; -+#else -+ iFormat = 1; -+#endif - } - - VpuDecRetCode CDVDVideoCodecIMXVPUBuffer::ReleaseFramebuffer(VpuDecHandle *handle) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 33e449f..c8b807d 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -127,16 +127,19 @@ class CDVDVideoCodecIMXVPUBuffer : public CDVDVideoCodecIMXBuffer - CDVDVideoCodecIMXVPUBuffer *previous); - VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); - CDVDVideoCodecIMXVPUBuffer *GetPreviousBuffer() const; -+ VpuFieldType GetFieldType() const { return m_fieldType; } - - private: - // private because we are reference counted -- virtual ~CDVDVideoCodecIMXVPUBuffer(); -+ virtual ~CDVDVideoCodecIMXVPUBuffer(); - - private: - VpuFrameBuffer *m_frameBuffer; -+ VpuFieldType m_fieldType; -+ - bool m_rendered; - CDVDVideoCodecIMXVPUBuffer *m_previousBuffer; // Holds a the reference counted -- // previous buffer -+ // previous buffer - }; - - - -From 9cb00a6922b74690e7502cd72dba98071297700e Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:46:32 +0100 -Subject: [PATCH 09/18] [imx] @wolfgar Added more VPU decoder configuration and - fixed nChromaInterleave depending on input format - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 87a6c48..c09b4e6 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -189,7 +189,11 @@ bool CDVDVideoCodecIMX::VpuOpen(void) - VpuAllocBuffers(&memInfo); - - m_decOpenParam.nReorderEnable = 1; -+#ifdef IMX_INPUT_FORMAT_I420 -+ m_decOpenParam.nChromaInterleave = 0; -+#else - m_decOpenParam.nChromaInterleave = 1; -+#endif - m_decOpenParam.nMapType = 0; - m_decOpenParam.nTiled2LinearEnable = 0; - m_decOpenParam.nEnableFileMode = 0; -@@ -210,6 +214,24 @@ bool CDVDVideoCodecIMX::VpuOpen(void) - goto VpuOpenError; - } - -+ config = VPU_DEC_CONF_BUFDELAY; -+ param = 0; -+ ret = VPU_DecConfig(m_vpuHandle, config, ¶m); -+ if (ret != VPU_DEC_RET_SUCCESS) -+ { -+ CLog::Log(LOGERROR, "%s - iMX VPU set buffer delay failed (%d).\n", __FUNCTION__, ret); -+ goto VpuOpenError; -+ } -+ -+ config = VPU_DEC_CONF_INPUTTYPE; -+ param = VPU_DEC_IN_NORMAL; -+ ret = VPU_DecConfig(m_vpuHandle, config, ¶m); -+ if (ret != VPU_DEC_RET_SUCCESS) -+ { -+ CLog::Log(LOGERROR, "%s - iMX VPU configure input type failed (%d).\n", __FUNCTION__, ret); -+ goto VpuOpenError; -+ } -+ - // Note that libvpufsl (file vpu_wrapper.c) associates VPU_DEC_CAP_FRAMESIZE - // capability to the value of nDecFrameRptEnabled which is in fact directly - // related to the ability to generate VPU_DEC_ONE_FRM_CONSUMED even if the - -From abe29f2acc6291d5807f34ed0fd9fd7ba83f8274 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:50:47 +0100 -Subject: [PATCH 10/18] [imx] @wolfgar Added deinterlacer initialization and - mixer thread but still unused - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 12 +++++++++++- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 3 +++ - 2 files changed, 14 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index c09b4e6..59187e8 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -385,16 +385,25 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) - #endif - } - -+ CLog::Log(LOGNOTICE, "IMX: Initialize hardware deinterlacing\n"); -+ if (!m_deinterlacer.Init(m_initInfo.nPicWidth, m_initInfo.nPicHeight, GetAllowedReferences()+5, nAlign)) -+ { -+ CLog::Log(LOGWARNING, "IMX: Failed to initialize IPU buffers: deinterlacing disabled\n"); -+ } -+ -+ m_deinterlacer.SetAutoMode(m_initInfo.nInterlace); -+ - return true; - } - --CDVDVideoCodecIMX::CDVDVideoCodecIMX() -+CDVDVideoCodecIMX::CDVDVideoCodecIMX() : m_mixer(&m_deinterlacer) - { - m_pFormatName = "iMX-xxx"; - m_vpuHandle = 0; - m_vpuFrameBuffers = NULL; - m_outputBuffers = NULL; - m_lastBuffer = NULL; -+ m_currentBuffer = NULL; - m_extraMem = NULL; - m_vpuFrameBufferNum = 0; - m_dropState = false; -@@ -409,6 +418,7 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() - m_convert_bitstream = false; - m_bytesToBeConsumed = 0; - m_previousPts = DVD_NOPTS_VALUE; -+ m_mixer.SetCapacity(3,3); - } - - CDVDVideoCodecIMX::~CDVDVideoCodecIMX() -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index c8b807d..69e27f7 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -330,8 +330,11 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec - bool m_dropState; // Current drop state - int m_vpuFrameBufferNum; // Total number of allocated frame buffers - VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description -+ CDVDVideoCodecIMXIPUBuffers m_deinterlacer; // Pool of buffers used for deinterlacing -+ CDVDVideoMixerIMX m_mixer; - CDVDVideoCodecIMXVPUBuffer **m_outputBuffers; // Table of VPU output buffers - CDVDVideoCodecIMXVPUBuffer *m_lastBuffer; // Keep track of previous VPU output buffer (needed by deinterlacing motion engin) -+ CDVDVideoCodecIMXBuffer *m_currentBuffer; - VpuMemDesc *m_extraMem; // Table of allocated extra Memory - int m_frameCounter; // Decoded frames counter - bool m_usePTS; // State whether pts out of decoding process should be used - -From f54fdf922228a37fb7d4f89177f4bd5c766a8026 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 19:56:14 +0100 -Subject: [PATCH 11/18] [imx] @wolfgar Cosmetics and removed duplicate class - declaration - ---- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 71 +++++++--------------- - 1 file changed, 21 insertions(+), 50 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 69e27f7..7c0e7da 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -187,60 +187,32 @@ class CDVDVideoCodecIMXIPUBuffer : public CDVDVideoCodecIMXBuffer - // buffers. - class CDVDVideoCodecIMXIPUBuffers - { -- public: -- CDVDVideoCodecIMXIPUBuffers(); -- ~CDVDVideoCodecIMXIPUBuffers(); -- -- bool Init(int width, int height, int numBuffers, int nAlign); -- // Sets the mode to be used if deinterlacing is set to AUTO -- void SetAutoMode(bool mode) { m_autoMode = mode; } -- bool AutoMode() const { return m_autoMode; } -- bool Reset(); -- bool Close(); -- -- CDVDVideoCodecIMXIPUBuffer * -- Process(CDVDVideoCodecIMXBuffer *sourceBuffer, -- VpuFieldType fieldType, bool lowMotion); -- -- private: -- int m_ipuHandle; -- bool m_autoMode; -- int m_bufferNum; -- CDVDVideoCodecIMXIPUBuffer **m_buffers; -- int m_currentFieldFmt; --}; -+public: -+ CDVDVideoCodecIMXIPUBuffers(); -+ ~CDVDVideoCodecIMXIPUBuffers(); - -+ bool Init(int width, int height, int numBuffers, int nAlign); -+ // Sets the mode to be used if deinterlacing is set to AUTO -+ void SetAutoMode(bool mode) { m_autoMode = mode; } -+ bool AutoMode() const { return m_autoMode; } -+ bool Reset(); -+ bool Close(); - --// Collection class that manages a pool of IPU buffers that are used for --// deinterlacing. In future they can also serve rotation or color conversion --// buffers. --class CDVDVideoCodecIMXIPUBuffers --{ -- public: -- CDVDVideoCodecIMXIPUBuffers(); -- ~CDVDVideoCodecIMXIPUBuffers(); -- -- bool Init(int width, int height, int numBuffers, int nAlign); -- // Sets the mode to be used if deinterlacing is set to AUTO -- void SetAutoMode(bool mode) { m_autoMode = mode; } -- bool AutoMode() const { return m_autoMode; } -- bool Reset(); -- bool Close(); -- -- CDVDVideoCodecIMXIPUBuffer * -- Process(CDVDVideoCodecIMXBuffer *sourceBuffer, -- VpuFieldType fieldType, bool lowMotion); -- -- private: -- int m_ipuHandle; -- bool m_autoMode; -- int m_bufferNum; -- CDVDVideoCodecIMXIPUBuffer **m_buffers; -- int m_currentFieldFmt; -+ CDVDVideoCodecIMXIPUBuffer * -+ Process(CDVDVideoCodecIMXBuffer *sourceBuffer, -+ VpuFieldType fieldType, bool lowMotion); -+ -+private: -+ int m_ipuHandle; -+ bool m_autoMode; -+ int m_bufferNum; -+ CDVDVideoCodecIMXIPUBuffer **m_buffers; -+ int m_currentFieldFmt; - }; - - --class CDVDVideoMixerIMX : private CThread { -+class CDVDVideoMixerIMX : private CThread -+{ - public: - CDVDVideoMixerIMX(CDVDVideoCodecIMXIPUBuffers *proc); - virtual ~CDVDVideoMixerIMX(); -@@ -309,7 +281,6 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec - static void Leave(); - - protected: -- - bool VpuOpen(); - bool VpuAllocBuffers(VpuMemInfo *); - bool VpuFreeBuffers(); - -From 5c8168ca2a215c52b7d2fba81de6b300df87586a Mon Sep 17 00:00:00 2001 -From: smallint -Date: Tue, 25 Nov 2014 20:00:17 +0100 -Subject: [PATCH 12/18] [imx6] @wolfgar Activated deinterlacer and mixer thread - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 53 +++++--- - xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 3 + - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 141 ++++++++++++--------- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 6 - - 4 files changed, 123 insertions(+), 80 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index b0229ef..037a57b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -89,7 +89,12 @@ static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR; - #include "windowing/egl/EGLWrapper.h" - #include "DVDCodecs/Video/DVDVideoCodecIMX.h" - -+#define GL_VIV_YV12 0x8FC0 - #define GL_VIV_NV12 0x8FC1 -+#define GL_VIV_YUY2 0x8FC2 -+#define GL_VIV_UYVY 0x8FC3 -+#define GL_VIV_NV21 0x8FC4 -+#define GL_VIV_I420 0x8FC5 - typedef void (GL_APIENTRYP PFNGLTEXDIRECTVIVMAPPROC) (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical); - typedef void (GL_APIENTRYP PFNGLTEXDIRECTINVALIDATEVIVPROC) (GLenum Target); - static PFNGLTEXDIRECTVIVMAPPROC glTexDirectVIVMap; -@@ -1237,7 +1242,7 @@ void CLinuxRendererGLES::RenderMultiPass(int index, int field) - // imgwidth *= planes[0].pixpertex_x; - // imgheight *= planes[0].pixpertex_y; - // } --// -+// - // glBegin(GL_QUADS); - // - // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1); -@@ -1683,18 +1688,23 @@ void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) - YUVPLANE &plane = m_buffers[index].fields[field][0]; - CDVDVideoCodecIMXBuffer *buffer = m_buffers[index].IMXBuffer; - -- if(buffer == NULL) return; -+#ifdef IMX_PROFILE_BUFFERS -+ static unsigned long long last = 0; -+ unsigned long long current = XbmcThreads::SystemClockMillis(); -+ CLog::Log(LOGNOTICE, "+R %x %lld\n", (int)buffer, current-last); -+ last = current; -+#endif - -- CDVDVideoCodecIMX::Enter(); -+ if(buffer == NULL) return; - - if(!buffer->IsValid()) - { -- CDVDVideoCodecIMX::Leave(); - return; - } - - glDisable(GL_DEPTH_TEST); - -+ glEnable(m_textureTarget); - glActiveTexture(GL_TEXTURE0); - glBindTexture(m_textureTarget, plane.id); - -@@ -1742,10 +1752,9 @@ void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) - VerifyGLState(); - - glBindTexture(m_textureTarget, 0); -+ glDisable(m_textureTarget); - VerifyGLState(); - -- CDVDVideoCodecIMX::Leave(); -- - #ifdef DEBUG_VERBOSE - CLog::Log(LOGDEBUG, "RenderIMXMAPTexture %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time); - #endif -@@ -2719,25 +2728,29 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) - - if(IMXBuffer) - { -- CDVDVideoCodecIMX::Enter(); -- - if(!IMXBuffer->IsValid()) - { -- CDVDVideoCodecIMX::Leave(); - return; - } - - YUVPLANE &plane = m_buffers[index].fields[0][0]; - -+ glEnable(m_textureTarget); - glActiveTexture(GL_TEXTURE0); -+ - glBindTexture(m_textureTarget, plane.id); - - GLuint physical = ~0U; - GLvoid *virt = (GLvoid*)IMXBuffer->pVirtAddr; -- glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_VIV_NV12, -- (GLvoid **)&virt, &physical); -- glTexDirectInvalidateVIV(m_textureTarget); - -+ if (IMXBuffer->iFormat == 0) -+ glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_VIV_I420, -+ (GLvoid **)&virt, &physical); -+ else -+ glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_VIV_NV12, -+ (GLvoid **)&virt, &physical); -+ -+ glTexDirectInvalidateVIV(m_textureTarget); - glBindTexture(m_textureTarget, 0); - - plane.flipindex = m_buffers[index].flipindex; -@@ -2746,7 +2759,7 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) - - CalculateTextureSourceRects(index, 1); - -- CDVDVideoCodecIMX::Leave(); -+ glDisable(m_textureTarget); - } - #endif - } -@@ -2864,9 +2877,6 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode) - if(m_renderMethod & RENDER_CVREF) - return false; - -- if(m_renderMethod & RENDER_IMXMAP) -- return false; -- - if(mode == VS_DEINTERLACEMODE_AUTO - || mode == VS_DEINTERLACEMODE_FORCE) - return true; -@@ -2901,6 +2911,15 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) - if(method == VS_INTERLACEMETHOD_AUTO) - return true; - -+ if(m_renderMethod & RENDER_IMXMAP) -+ { /* -+ if(method == VS_INTERLACEMETHOD_DEINTERLACE -+ || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF) -+ return true; -+ else*/ -+ return false; -+ } -+ - #if defined(__i386__) || defined(__x86_64__) - if(method == VS_INTERLACEMETHOD_DEINTERLACE - || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF -@@ -2966,6 +2985,8 @@ unsigned int CLinuxRendererGLES::GetOptimalBufferSize() - m_format == RENDER_FMT_EGLIMG || - m_format == RENDER_FMT_MEDIACODEC) - return 2; -+ else if(m_format == RENDER_FMT_IMXMAP) -+ return 1; - else - return 3; - } -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -index d8bf35d..0532c19 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h -@@ -42,6 +42,9 @@ namespace Shaders { class BaseVideoFilterShader; } - class COpenMaxVideo; - class CDVDVideoCodecStageFright; - class CDVDMediaCodecInfo; -+#ifdef HAS_IMXVPU -+class CDVDVideoCodecIMXBuffer; -+#endif - typedef std::vector Features; - - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 59187e8..f841380 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -44,7 +44,6 @@ - // Experiments show that we need at least one more (+1) VPU buffer than the min value returned by the VPU - const int CDVDVideoCodecIMX::m_extraVpuBuffers = 6; - const int CDVDVideoCodecIMX::m_maxVpuDecodeLoops = 5; --CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock; - - bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) - { -@@ -557,6 +556,8 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) - return false; - } - -+ m_mixer.Start(); -+ - return true; - } - -@@ -565,12 +566,12 @@ void CDVDVideoCodecIMX::Dispose(void) - VpuDecRetCode ret; - bool VPU_loaded = m_vpuHandle; - -- // Prevent rendering thread from using frame buffers -- Enter(); -+ // Dispose the mixer thread -+ m_mixer.Dispose(); - - // Release last buffer -- if(m_lastBuffer) -- SAFE_RELEASE(m_lastBuffer); -+ SAFE_RELEASE(m_lastBuffer); -+ SAFE_RELEASE(m_currentBuffer); - - // Invalidate output buffers to prevent the renderer from mapping this memory - for (int i=0; inFrmWidth = (((m_frameInfo.pExtInfo->nFrmWidth) + 15) & ~15); - m_frameInfo.pExtInfo->nFrmHeight = (((m_frameInfo.pExtInfo->nFrmHeight) + 15) & ~15); - -- /* quick & dirty fix to get proper timestamping for VP8 codec */ -- if (m_decOpenParam.CodecFormat == VPU_V_VP8) -+ idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); -+ if (idx != -1) - { -- idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); -- m_outputBuffers[idx]->SetPts(pts); -- } -+ CDVDVideoCodecIMXVPUBuffer *buffer = m_outputBuffers[idx]; -+ /* quick & dirty fix to get proper timestamping for VP8 codec */ -+ if (m_decOpenParam.CodecFormat == VPU_V_VP8) -+ buffer->SetPts(pts); - -- retStatus |= VC_PICTURE; -+ buffer->Lock(); -+ buffer->SetDts(dts); -+ buffer->Queue(&m_frameInfo, m_lastBuffer); -+ -+#ifdef IMX_PROFILE_BUFFERS -+ CLog::Log(LOGNOTICE, "+D %x %lld\n", buffer, dec_time); -+ dec_time = 0; -+#endif -+ -+#ifdef TRACE_FRAMES -+ CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); -+#endif -+ -+ if (!m_usePTS) -+ { -+ buffer->SetPts(DVD_NOPTS_VALUE); -+ buffer->SetDts(DVD_NOPTS_VALUE); -+ } -+ -+ // Save last buffer -+ SAFE_RELEASE(m_lastBuffer); -+ m_lastBuffer = buffer; -+ m_lastBuffer->Lock(); -+ -+#ifdef IMX_PROFILE_BUFFERS -+ static unsigned long long lastD = 0; -+ unsigned long long current = XbmcThreads::SystemClockMillis(), tmp; -+ CLog::Log(LOGNOTICE, "+V %x %lld\n", buffer, current-lastD); -+ lastD = current; -+#endif -+ -+ //m_currentBuffer = buffer; -+ if (m_dropState) -+ { -+ m_currentBuffer = m_mixer.Process(NULL); -+ if (!m_currentBuffer) -+ m_currentBuffer = buffer; -+ else -+ buffer->Release(); -+ } -+ else -+ m_currentBuffer = m_mixer.Process(buffer); -+ -+ if (m_currentBuffer) -+ { -+ retStatus |= VC_PICTURE; -+ //m_currentBuffer->Release(); -+ //m_currentBuffer = NULL; -+ } -+ } - } //VPU_DEC_OUTPUT_DIS - - // According to libfslvpuwrap: If this flag is set then the frame should -@@ -901,8 +960,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) - // at next call... - m_previousPts = pts; - } -- // Store current dts (will be used only if VC_PICTURE is set) -- m_dts = dts; - - #ifdef IMX_PROFILE - CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, XbmcThreads::SystemClockMillis() - previous); -@@ -920,9 +977,13 @@ void CDVDVideoCodecIMX::Reset() - if (g_advancedSettings.CanLogComponent(LOGVIDEO)) - CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); - -+ // Restart mixer -+ m_mixer.Dispose(); -+ m_mixer.Start(); -+ - // Release last buffer -- if(m_lastBuffer) -- SAFE_RELEASE(m_lastBuffer); -+ SAFE_RELEASE(m_lastBuffer); -+ SAFE_RELEASE(m_currentBuffer); - - // Invalidate all buffers - for(int i=0; i < m_vpuFrameBufferNum; i++) -@@ -983,38 +1044,12 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) - pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; - pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; - -- int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); -- if (idx != -1) -- { -- CDVDVideoCodecIMXVPUBuffer *buffer = m_outputBuffers[idx]; -- -- pDvdVideoPicture->pts = buffer->GetPts(); -- pDvdVideoPicture->dts = m_dts; -- if (!m_usePTS) -- { -- pDvdVideoPicture->pts = DVD_NOPTS_VALUE; -- pDvdVideoPicture->dts = DVD_NOPTS_VALUE; -- } -- -- buffer->Queue(&m_frameInfo, m_lastBuffer); -- --#ifdef TRACE_FRAMES -- CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); --#endif -- -- pDvdVideoPicture->IMXBuffer = buffer; -- pDvdVideoPicture->IMXBuffer->Lock(); -+ // Current buffer is locked already -> hot potato -+ pDvdVideoPicture->pts = m_currentBuffer->GetPts(); -+ pDvdVideoPicture->dts = m_currentBuffer->GetDts(); - -- // Save last buffer -- if (m_lastBuffer) -- SAFE_RELEASE(m_lastBuffer); -- m_lastBuffer = buffer; -- m_lastBuffer->Lock(); -- } -- else -- { -- CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); -- } -+ pDvdVideoPicture->IMXBuffer = m_currentBuffer; -+ m_currentBuffer = NULL; - - return true; - } -@@ -1035,16 +1070,6 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) - } - } - --void CDVDVideoCodecIMX::Enter() --{ -- m_codecBufferLock.lock(); --} -- --void CDVDVideoCodecIMX::Leave() --{ -- m_codecBufferLock.unlock(); --} -- - /*******************************************/ - #ifdef TRACE_FRAMES - CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx) -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 7c0e7da..6af8130 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -277,9 +277,6 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec - virtual const char* GetName(void) { return (const char*)m_pFormatName; } - virtual unsigned GetAllowedReferences(); - -- static void Enter(); -- static void Leave(); -- - protected: - bool VpuOpen(); - bool VpuAllocBuffers(VpuMemInfo *); -@@ -289,8 +286,6 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec - - static const int m_extraVpuBuffers; // Number of additional buffers for VPU - static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop -- static CCriticalSection m_codecBufferLock; // Lock to protect buffers handled -- // by both decoding and rendering threads - - CDVDStreamInfo m_hints; // Hints from demuxer at stream opening - const char *m_pFormatName; // Current decoder format name -@@ -315,5 +310,4 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec - int m_bytesToBeConsumed; // Remaining bytes in VPU - double m_previousPts; // Enable to keep pts when needed - bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu -- double m_dts; // Current dts - }; - -From a9f1458a4b43f722db4d115e1b5e0a1c4d81f72f Mon Sep 17 00:00:00 2001 -From: smallint -Date: Wed, 26 Nov 2014 01:11:54 +0100 -Subject: [PATCH 13/18] [imx] @wolfgar return 3 in - LinuxRendererGLES::GetOptimalBufferSize for IMX render path - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 037a57b..35c905b 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -2986,7 +2986,7 @@ unsigned int CLinuxRendererGLES::GetOptimalBufferSize() - m_format == RENDER_FMT_MEDIACODEC) - return 2; - else if(m_format == RENDER_FMT_IMXMAP) -- return 1; -+ return 3; - else - return 3; - } - -From b3c24108ad8f61989f9fbbeab605c021782889f4 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Thu, 27 Nov 2014 22:39:10 +0100 -Subject: [PATCH 14/18] [imx] @wolfgar Corrected some comments, fixed iFormat - along with IMX_OUTPUT_FORMAT_I420 - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 9 +++++---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 4 ++-- - 2 files changed, 7 insertions(+), 6 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index f841380..511956d 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -644,6 +644,8 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) - - #ifdef IMX_PROFILE - static unsigned long long previous, current; -+#endif -+#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) - unsigned long long before_dec; - #endif - -@@ -711,12 +713,11 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) - - while (true) // Decode as long as the VPU consumes data - { --#ifdef IMX_PROFILE -+#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) - before_dec = XbmcThreads::SystemClockMillis(); - #endif - if (m_frameReported) - m_bytesToBeConsumed += inData.nSize; -- unsigned long long before_dec = XbmcThreads::SystemClockMillis(); - ret = VPU_DecDecodeBuf(m_vpuHandle, &inData, &decRet); - #ifdef IMX_PROFILE_BUFFERS - dec_time += XbmcThreads::SystemClockMillis()-before_dec; -@@ -1125,7 +1126,7 @@ long CDVDVideoCodecIMXVPUBuffer::Release() - #endif - if (count == 2) - { -- // Only referenced by the coded and its next frame, release the previous -+ // Only referenced by the codec and its next frame, release the previous - SAFE_RELEASE(m_previousBuffer); - } - if (count == 1) -@@ -1308,7 +1309,7 @@ bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buf - task.output.height = iHeight; - #ifdef IMX_OUTPUT_FORMAT_I420 - task.output.format = IPU_PIX_FMT_YUV420P; -- format = 0; -+ iFormat = 0; - #else - task.output.format = IPU_PIX_FMT_NV12; - iFormat = 1; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index 6af8130..d9aadc9 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -38,8 +38,8 @@ - // The IPU works faster when outputting to NV12. - //#define IMX_OUTPUT_FORMAT_I420 - --// This enables logging of times for Decode->Decode, Render->Render, --// Deinterlace->Deinterlace. It helps to profile several stages of -+// This enables logging of times for Decode, Render->Render, -+// Deinterlace. It helps to profile several stages of - // processing with respect to changed kernels or other configurations. - // Since we utilize VPU, IPU and GPU at the same time different kernel - // priorities to those subsystems can result in a very different user - -From 4eff53acf4e0dfe892a484ec7355bc60aafda6c0 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Thu, 27 Nov 2014 22:42:36 +0100 -Subject: [PATCH 15/18] [imx] @wolfgar Enable LOW_MOTION for SD content - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 511956d..51ec5d8 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -1818,9 +1818,11 @@ CDVDVideoCodecIMXBuffer *CDVDVideoMixerIMX::ProcessFrame(CDVDVideoCodecIMXVPUBuf - Sleep(35); - outputBuffer = inputBuffer; - #else -+ // Enable low motion for buffers that are not split up by the VDIC -+ bool lowMotion = (inputBuffer->iWidth < 1024) && (inputBuffer->iHeight < 1024); - outputBuffer = m_proc->Process(inputBuffer, - inputBuffer->GetFieldType(), -- false); -+ lowMotion); - #endif - #ifdef IMX_PROFILE_BUFFERS - CLog::Log(LOGNOTICE, "+P %x %lld\n", (int)outputBuffer, - -From 021f9599d77a0579f278c3f8d4a9ea474f71c177 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Fri, 28 Nov 2014 23:42:09 +0100 -Subject: [PATCH 16/18] [imx] @wolfgar Removed commented lines and removed - WRITE flag for read only mapped buffers - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index 51ec5d8..d20028f 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -864,11 +864,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) - m_currentBuffer = m_mixer.Process(buffer); - - if (m_currentBuffer) -- { - retStatus |= VC_PICTURE; -- //m_currentBuffer->Release(); -- //m_currentBuffer = NULL; -- } - } - } //VPU_DEC_OUTPUT_DIS - -@@ -1400,7 +1396,7 @@ bool CDVDVideoCodecIMXIPUBuffer::Allocate(int fd, int width, int height, int nAl - CLog::Log(LOGNOTICE, "IPU: alloc %d bytes for frame of %dx%d at 0x%x\n", - m_nSize, m_iWidth, m_iHeight, m_pPhyAddr); - -- m_pVirtAddr = (uint8_t*)mmap(0, m_nSize, PROT_READ | PROT_WRITE, MAP_SHARED, -+ m_pVirtAddr = (uint8_t*)mmap(0, m_nSize, PROT_READ, MAP_SHARED, - fd, m_pPhyAddr); - if (!m_pVirtAddr) - { - -From ea72d307c53eb417c6d2bb898cae438e34b62c89 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Fri, 5 Dec 2014 17:02:36 +0000 -Subject: [PATCH 17/18] [imx] @wolfgar Added VDI buffer splitting to bypass - kernel splitting algorithms which introduces some DMA memory burst penalties - ---- - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 8 ++- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 62 +++++++++++++++++++--- - .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 17 ++++-- - 3 files changed, 76 insertions(+), 11 deletions(-) - -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -index 35c905b..0364a6c 100644 ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp -@@ -2746,9 +2746,15 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) - if (IMXBuffer->iFormat == 0) - glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_VIV_I420, - (GLvoid **)&virt, &physical); -- else -+ else if (IMXBuffer->iFormat == 1) - glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_VIV_NV12, - (GLvoid **)&virt, &physical); -+ else if (IMXBuffer->iFormat == 2) -+ glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_RGB565, -+ (GLvoid **)&virt, &physical); -+ else if (IMXBuffer->iFormat == 3) -+ glTexDirectVIVMap(m_textureTarget, IMXBuffer->iWidth, IMXBuffer->iHeight, GL_RGBA, -+ (GLvoid **)&virt, &physical); - - glTexDirectInvalidateVIV(m_textureTarget); - glBindTexture(m_textureTarget, 0); -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index d20028f..f556223 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -36,6 +36,7 @@ - #include "utils/log.h" - #include "DVDClock.h" - -+#define IMX_MDI_MAX_WIDTH 968 - #define FRAME_ALIGN 16 - #define MEDIAINFO 1 - #define _4CC(c1,c2,c3,c4) (((uint32_t)(c4)<<24)|((uint32_t)(c3)<<16)|((uint32_t)(c2)<<8)|(uint32_t)(c1)) -@@ -1294,6 +1295,8 @@ bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buf - // Input is the VPU decoded frame - task.input.width = iWidth; - task.input.height = iHeight; -+ task.input.crop.h = iHeight; -+ - #ifdef IMX_INPUT_FORMAT_I420 - task.input.format = IPU_PIX_FMT_YUV420P; - #else -@@ -1303,6 +1306,7 @@ bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buf - // Output is our IPU buffer - task.output.width = iWidth; - task.output.height = iHeight; -+ task.output.crop.h = iHeight; - #ifdef IMX_OUTPUT_FORMAT_I420 - task.output.format = IPU_PIX_FMT_YUV420P; - iFormat = 0; -@@ -1310,6 +1314,14 @@ bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buf - task.output.format = IPU_PIX_FMT_NV12; - iFormat = 1; - #endif -+#ifdef IMX_OUTPUT_FORMAT_RGB565 -+ task.output.format = IPU_PIX_FMT_RGB565; -+ iFormat = 2; -+#endif -+#ifdef IMX_OUTPUT_FORMAT_RGB32 -+ task.output.format = IPU_PIX_FMT_RGB32; -+ iFormat = 3; -+#endif - task.output.paddr = (int)pPhysAddr; - - // Fill current and next buffer address -@@ -1345,15 +1357,42 @@ bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buf - #ifdef IMX_PROFILE - unsigned int time = XbmcThreads::SystemClockMillis(); - #endif -- int ret = ioctl(fd, IPU_QUEUE_TASK, &task); -+ -+ /* We do the VDI buffer splitting ourselves since the kernel -+ * driver (IPU) is either buggy or it is a feature that it does -+ * not split widths to multiple of 16 to get maximum burst on -+ * on DMA. Since we know that the input and output dimensions are the -+ * same we can implement an easier algorithm that takes care of -+ * that. -+ */ -+ unsigned int nRequiredStripes = (iWidth+IMX_MDI_MAX_WIDTH-1) / IMX_MDI_MAX_WIDTH; -+ unsigned int iProcWidth = iWidth; -+ unsigned int iStripeOffset = 0; -+ -+ while (iStripeOffset < iWidth) -+ { -+ unsigned int iStripeWidth = Align(iWidth/nRequiredStripes, FRAME_ALIGN); -+ if (iStripeWidth > iProcWidth) -+ iStripeWidth = iProcWidth; -+ -+ task.input.crop.pos.x = iStripeOffset; -+ task.input.crop.w = iStripeWidth; -+ task.output.crop.pos.x = task.input.crop.pos.x; -+ task.output.crop.w = task.input.crop.w; -+ -+ if (ioctl(fd, IPU_QUEUE_TASK, &task) < 0) -+ { -+ CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno)); -+ return false; -+ } -+ -+ iStripeOffset += iStripeWidth; -+ iProcWidth -= iStripeWidth; -+ } -+ - #ifdef IMX_PROFILE - CLog::Log(LOGDEBUG, "DEINT: tm:%d\n", XbmcThreads::SystemClockMillis() - time); - #endif -- if (ret < 0) -- { -- CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno)); -- return false; -- } - - m_bFree = false; - buffer->Lock(); -@@ -1379,8 +1418,19 @@ bool CDVDVideoCodecIMXIPUBuffer::Allocate(int fd, int width, int height, int nAl - { - m_iWidth = Align(width,FRAME_ALIGN); - m_iHeight = Align(height,(2*FRAME_ALIGN)); -+#if defined(IMX_OUTPUT_FORMAT_NV12) || defined(IMX_OUTPUT_FORMAT_I420) - // I420 == 12 bpp - m_nSize = m_iWidth*m_iHeight*12/8; -+#endif -+#ifdef IMX_OUTPUT_FORMAT_RGB565 -+ // RGB565 = 16 bpp -+ m_nSize = m_iWidth*m_iHeight*16/8; -+#endif -+#ifdef IMX_OUTPUT_FORMAT_RGB32 -+ // RGB32 = 32 bpp -+ m_nSize = m_iWidth*m_iHeight*32/8; -+#endif -+ - m_pPhyAddr = m_nSize; - - pPhysAddr = pVirtAddr = NULL; -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -index d9aadc9..f44168b 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h -@@ -31,12 +31,16 @@ - - - // The decoding format of the VPU buffer. Comment this to decode --// as NV12. The VPU works faster with I420. --#define IMX_INPUT_FORMAT_I420 -+// as NV12. The VPU works faster with NV12 in combination with -+// deinterlacing. -+//#define IMX_INPUT_FORMAT_I420 - --// The deinterlacer output and render format. Uncomment to use I420. --// The IPU works faster when outputting to NV12. -+// The deinterlacer output and render format. Only one format must be active -+// at a time -+#define IMX_OUTPUT_FORMAT_NV12 - //#define IMX_OUTPUT_FORMAT_I420 -+//#define IMX_OUTPUT_FORMAT_RGB565 -+//#define IMX_OUTPUT_FORMAT_RGB32 - - // This enables logging of times for Decode, Render->Render, - // Deinterlace. It helps to profile several stages of -@@ -50,6 +54,11 @@ - //#define IMX_PROFILE - //#define TRACE_FRAMES - -+// If uncommented a file "stream.dump" will be created in the current -+// directory whenever a new stream is started. This is only for debugging -+// and performance tests. This define must never be active in distributions. -+//#define DUMP_STREAM -+ - class CDecMemInfo - { - public: - -From 3c6b55e684e821c0ddedcd8fbb86b19363ce8f39 Mon Sep 17 00:00:00 2001 -From: smallint -Date: Fri, 5 Dec 2014 17:58:36 +0000 -Subject: [PATCH 18/18] [imx] @wolfgar Removed IPU task priority setting - ---- - xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -index f556223..5c2b021 100644 ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp -@@ -1281,7 +1281,6 @@ bool CDVDVideoCodecIMXIPUBuffer::Process(int fd, CDVDVideoCodecIMXVPUBuffer *buf - CDVDVideoCodecIMXVPUBuffer *previousBuffer; - struct ipu_task task; - memset(&task, 0, sizeof(task)); -- task.priority = IPU_TASK_PRIORITY_HIGH; - - if (lowMotion) - previousBuffer = buffer->GetPreviousBuffer(); diff --git a/projects/imx6/patches/kodi/kodi-01-renderer-drop-old-tempfix-firstflippage-did-not-work.patch b/projects/imx6/patches/kodi/kodi-01-renderer-drop-old-tempfix-firstflippage-did-not-work.patch new file mode 100644 index 0000000000..b1305576d7 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-01-renderer-drop-old-tempfix-firstflippage-did-not-work.patch @@ -0,0 +1,99 @@ +From 5aed65d63d71073340a4b4c7da814a67a8e814a7 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Fri, 2 Jan 2015 10:02:09 +0100 +Subject: [PATCH 1/6] renderer: drop old tempfix firstflippage, did not work + anyway because RendererHandlesPresent returned always true + +--- + xbmc/Application.cpp | 2 +- + xbmc/cores/VideoRenderers/RenderManager.cpp | 9 --------- + xbmc/cores/VideoRenderers/RenderManager.h | 5 ----- + xbmc/guilib/GUIVideoControl.cpp | 3 +-- + 4 files changed, 2 insertions(+), 17 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 7ee0a34..1c717c2 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2222,7 +2222,7 @@ void CApplication::Render() + bool extPlayerActive = m_pPlayer->GetCurrentPlayer() == EPC_EXTPLAYER && m_pPlayer->IsPlaying() && !m_AppFocused; + + m_bPresentFrame = false; +- if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback() && g_renderManager.RendererHandlesPresent()) ++ if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback()) + { + m_bPresentFrame = g_renderManager.FrameWait(100); + hasRendered = true; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index b31f3c9..ab894ba 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -293,19 +293,12 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + m_sleeptime = 1.0; + m_presentevent.notifyAll(); + +- m_firstFlipPage = false; // tempfix +- + CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize); + } + + return result; + } + +-bool CXBMCRenderManager::RendererHandlesPresent() const +-{ +- return IsConfigured() && (m_firstFlipPage || m_format != RENDER_FMT_BYPASS); +-} +- + bool CXBMCRenderManager::IsConfigured() const + { + if (!m_pRenderer) +@@ -661,8 +654,6 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + + if(!m_pRenderer) return; + +- m_firstFlipPage = true; // tempfix +- + EPRESENTMETHOD presentmethod; + + EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index d3c2f1d..1086066 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -143,8 +143,6 @@ public: + + void UpdateResolution(); + +- bool RendererHandlesPresent() const; +- + #ifdef HAS_GL + CLinuxRendererGL *m_pRenderer; + #elif defined(HAS_MMAL) +@@ -267,9 +265,6 @@ protected: + //set to true when adding something to m_captures, set to false when m_captures is made empty + //std::list::empty() isn't thread safe, using an extra bool will save a lock per render when no captures are requested + bool m_hasCaptures; +- +- // temporary fix for RendererHandlesPresent after #2811 +- bool m_firstFlipPage; + }; + + extern CXBMCRenderManager g_renderManager; +diff --git a/xbmc/guilib/GUIVideoControl.cpp b/xbmc/guilib/GUIVideoControl.cpp +index 22d0fc8..c47a6d5 100644 +--- a/xbmc/guilib/GUIVideoControl.cpp ++++ b/xbmc/guilib/GUIVideoControl.cpp +@@ -43,8 +43,7 @@ CGUIVideoControl::~CGUIVideoControl(void) + void CGUIVideoControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) + { + // TODO Proper processing which marks when its actually changed. Just mark always for now. +- if (g_renderManager.RendererHandlesPresent()) +- MarkDirtyRegion(); ++ MarkDirtyRegion(); + + CGUIControl::Process(currentTime, dirtyregions); + } +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-02-Set-dirty-flag-in-teletext-dialog-if-required.patch b/projects/imx6/patches/kodi/kodi-02-Set-dirty-flag-in-teletext-dialog-if-required.patch new file mode 100644 index 0000000000..0795f6c093 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-02-Set-dirty-flag-in-teletext-dialog-if-required.patch @@ -0,0 +1,95 @@ +From a14f5348c5ce76ca074630c8bf0bfc3b6bf3f767 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Fri, 2 Jan 2015 15:35:33 +0000 +Subject: [PATCH 2/6] Set dirty flag in teletext dialog if required + +--- + xbmc/video/dialogs/GUIDialogTeletext.cpp | 19 +++++++++++++++++++ + xbmc/video/dialogs/GUIDialogTeletext.h | 1 + + 2 files changed, 20 insertions(+) + +diff --git a/xbmc/video/dialogs/GUIDialogTeletext.cpp b/xbmc/video/dialogs/GUIDialogTeletext.cpp +index c552ae6..9be4548 100644 +--- a/xbmc/video/dialogs/GUIDialogTeletext.cpp ++++ b/xbmc/video/dialogs/GUIDialogTeletext.cpp +@@ -46,7 +46,10 @@ CGUIDialogTeletext::~CGUIDialogTeletext() + bool CGUIDialogTeletext::OnAction(const CAction& action) + { + if (m_TextDecoder.HandleAction(action)) ++ { ++ MarkDirtyRegion(); + return true; ++ } + + return CGUIDialog::OnAction(action); + } +@@ -54,6 +57,7 @@ bool CGUIDialogTeletext::OnAction(const CAction& action) + bool CGUIDialogTeletext::OnBack(int actionID) + { + m_bClose = true; ++ MarkDirtyRegion(); + return true; + } + +@@ -79,6 +83,12 @@ bool CGUIDialogTeletext::OnMessage(CGUIMessage& message) + return CGUIDialog::OnMessage(message); + } + ++void CGUIDialogTeletext::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) ++{ ++ CGUIDialog::Process(currentTime, dirtyregions); ++ m_renderRegion = m_vertCoords; ++} ++ + void CGUIDialogTeletext::Render() + { + // Do not render if we have no texture +@@ -93,12 +103,18 @@ void CGUIDialogTeletext::Render() + if (!m_bClose) + { + if (teletextFadeAmount < 100) ++ { + teletextFadeAmount = std::min(100, teletextFadeAmount + 5); ++ MarkDirtyRegion(); ++ } + } + else + { + if (teletextFadeAmount > 0) ++ { + teletextFadeAmount = std::max(0, teletextFadeAmount - 10); ++ MarkDirtyRegion(); ++ } + + if (teletextFadeAmount == 0) + Close(); +@@ -109,6 +125,7 @@ void CGUIDialogTeletext::Render() + { + m_pTxtTexture->Update(m_TextDecoder.GetWidth(), m_TextDecoder.GetHeight(), m_TextDecoder.GetWidth()*4, XB_FMT_A8R8G8B8, textureBuffer, false); + m_TextDecoder.RenderingDone(); ++ MarkDirtyRegion(); + } + + color_t color = ((color_t)(teletextFadeAmount * 2.55f) & 0xff) << 24 | 0xFFFFFF; +@@ -184,4 +201,6 @@ void CGUIDialogTeletext::SetCoordinates() + top, + right, + bottom); ++ ++ MarkDirtyRegion(); + } +diff --git a/xbmc/video/dialogs/GUIDialogTeletext.h b/xbmc/video/dialogs/GUIDialogTeletext.h +index 51aced5..e8e11f8 100644 +--- a/xbmc/video/dialogs/GUIDialogTeletext.h ++++ b/xbmc/video/dialogs/GUIDialogTeletext.h +@@ -32,6 +32,7 @@ public: + virtual bool OnMessage(CGUIMessage& message); + virtual bool OnAction(const CAction& action); + virtual bool OnBack(int actionID); ++ virtual void Process(unsigned int currentTime, CDirtyRegionList &dirtyregions); + virtual void Render(); + virtual void OnInitWindow(); + virtual void OnDeinitWindow(int nextWindowID); +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-03-renderer-improve-rendering-to-gui-and-separate-video.patch b/projects/imx6/patches/kodi/kodi-03-renderer-improve-rendering-to-gui-and-separate-video.patch new file mode 100644 index 0000000000..d90cb18964 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-03-renderer-improve-rendering-to-gui-and-separate-video.patch @@ -0,0 +1,659 @@ +From 12021a04a6662400ed2bfffd0f2a752af89a6643 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Sat, 16 Aug 2014 17:29:15 +0200 +Subject: [PATCH 3/6] renderer: improve rendering to gui and separate video + layer + +--- + xbmc/Application.cpp | 10 +--- + xbmc/cores/VideoRenderers/BaseRenderer.h | 1 + + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 52 +++++++++++++-------- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 2 + + xbmc/cores/VideoRenderers/MMALRenderer.cpp | 15 ------ + xbmc/cores/VideoRenderers/MMALRenderer.h | 1 + + xbmc/cores/VideoRenderers/OverlayRenderer.cpp | 18 +++++++ + xbmc/cores/VideoRenderers/OverlayRenderer.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 62 ++++++++++++++++++++----- + xbmc/cores/VideoRenderers/RenderManager.h | 5 +- + xbmc/guilib/GUIControl.h | 3 ++ + xbmc/guilib/GUIControlGroup.cpp | 7 +++ + xbmc/guilib/GUIControlGroup.h | 1 + + xbmc/guilib/GUIVideoControl.cpp | 31 ++++++++++++- + xbmc/guilib/GUIVideoControl.h | 1 + + xbmc/guilib/GUIWindowManager.cpp | 22 ++++++++- + xbmc/guilib/GUIWindowManager.h | 1 + + xbmc/video/windows/GUIWindowFullScreen.cpp | 31 ++++++++++++- + xbmc/video/windows/GUIWindowFullScreen.h | 2 + + 19 files changed, 204 insertions(+), 62 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 1c717c2..137872c 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2170,9 +2170,6 @@ bool CApplication::RenderNoPresent() + // dont show GUI when playing full screen video + if (g_graphicsContext.IsFullScreenVideo()) + { +- g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetVideoResolution(), false); +- g_renderManager.Render(true, 0, 255); +- + // close window overlays + CGUIDialog *overlay = (CGUIDialog *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_OVERLAY); + if (overlay) overlay->Close(true); +@@ -2225,7 +2222,6 @@ void CApplication::Render() + if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback()) + { + m_bPresentFrame = g_renderManager.FrameWait(100); +- hasRendered = true; + } + else + { +@@ -2268,8 +2264,6 @@ void CApplication::Render() + if(!g_Windowing.BeginRender()) + return; + +- g_renderManager.FrameMove(); +- + CDirtyRegionList dirtyRegions = g_windowManager.GetDirty(); + if(g_graphicsContext.GetStereoMode()) + { +@@ -2291,8 +2285,6 @@ void CApplication::Render() + hasRendered = true; + } + +- g_renderManager.FrameFinish(); +- + g_Windowing.EndRender(); + + // execute post rendering actions (finalize window closing) +@@ -2317,7 +2309,7 @@ void CApplication::Render() + flip = true; + + //fps limiter, make sure each frame lasts at least singleFrameTime milliseconds +- if (limitFrames || !flip) ++ if (limitFrames || !(flip || m_bPresentFrame)) + { + if (!limitFrames) + singleFrameTime = 40; //if not flipping, loop at 25 fps +diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.h b/xbmc/cores/VideoRenderers/BaseRenderer.h +index 850aa6f..8988e35 100644 +--- a/xbmc/cores/VideoRenderers/BaseRenderer.h ++++ b/xbmc/cores/VideoRenderers/BaseRenderer.h +@@ -94,6 +94,7 @@ public: + virtual void SetBufferSize(int numBuffers) { } + virtual void ReleaseBuffer(int idx) { } + virtual bool NeedBufferForRef(int idx) { return false; } ++ virtual bool IsGuiLayer() { return true; } + + virtual bool Supports(ERENDERFEATURE feature) { return false; } + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 81fe19b..a765461 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -526,32 +526,16 @@ void CLinuxRendererGLES::Update() + + void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + { +- if (!m_bConfigured) return; ++ if (!m_bConfigured) ++ return; + + // if its first pass, just init textures and return + if (ValidateRenderTarget()) + return; + +- if (m_renderMethod & RENDER_BYPASS) ++ if (!IsGuiLayer()) + { +- 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); +- +- 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(); ++ RenderUpdateVideo(clear, flags, alpha); + return; + } + +@@ -606,6 +590,26 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + g_graphicsContext.EndPaint(); + } + ++void CLinuxRendererGLES::RenderUpdateVideo(bool clear, DWORD flags, DWORD alpha) ++{ ++ if (!m_bConfigured) ++ return; ++ ++ if (IsGuiLayer()) ++ return; ++ ++ if (m_renderMethod & RENDER_BYPASS) ++ { ++ 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); ++ ++ return; ++ } ++} ++ + void CLinuxRendererGLES::FlipPage(int source) + { + if( source >= 0 && source < m_NumYV12Buffers ) +@@ -3055,5 +3059,13 @@ void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecIMXBuffer *buffer, int index + } + #endif + ++bool CLinuxRendererGLES::IsGuiLayer() ++{ ++ if (m_format == RENDER_FMT_BYPASS) ++ return false; ++ else ++ return true; ++} ++ + #endif + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index d8bf35d..b865033 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -144,6 +144,7 @@ public: + virtual void SetBufferSize(int numBuffers) { m_NumYV12Buffers = numBuffers; } + virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } + virtual unsigned int GetOptimalBufferSize(); ++ virtual bool IsGuiLayer(); + + virtual void RenderUpdate(bool clear, DWORD flags = 0, DWORD alpha = 255); + +@@ -177,6 +178,7 @@ public: + + protected: + virtual void Render(DWORD flags, int index); ++ void RenderUpdateVideo(bool clear, DWORD flags = 0, DWORD alpha = 255); + + int NextYV12Texture(); + virtual bool ValidateRenderTarget(); +diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.cpp b/xbmc/cores/VideoRenderers/MMALRenderer.cpp +index 03a05de..69ff30a 100644 +--- a/xbmc/cores/VideoRenderers/MMALRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/MMALRenderer.cpp +@@ -347,21 +347,6 @@ void CMMALRenderer::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + // 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 CMMALRenderer::FlipPage(int source) +diff --git a/xbmc/cores/VideoRenderers/MMALRenderer.h b/xbmc/cores/VideoRenderers/MMALRenderer.h +index 8ca0b94..62d513e 100644 +--- a/xbmc/cores/VideoRenderers/MMALRenderer.h ++++ b/xbmc/cores/VideoRenderers/MMALRenderer.h +@@ -90,6 +90,7 @@ public: + virtual unsigned int GetMaxBufferSize() { return NUM_BUFFERS; } + virtual unsigned int GetOptimalBufferSize() { return NUM_BUFFERS; } + virtual void SetVideoRect(const CRect& SrcRect, const CRect& DestRect); ++ virtual bool IsGuiLayer() { return false; } + + void vout_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer); + protected: +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +index ea07d9f..e8c4bec 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.cpp ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.cpp +@@ -306,6 +306,24 @@ void CRenderer::Render(COverlay* o, float adjust_height) + o->Render(state); + } + ++bool CRenderer::HasOverlay(int idx) ++{ ++ bool hasOverlay = false; ++ ++ CSingleLock lock(m_section); ++ ++ SElementV& list = m_buffers[idx]; ++ for(SElementV::iterator it = list.begin(); it != list.end(); ++it) ++ { ++ if (it->overlay || it->overlay_dvd) ++ { ++ hasOverlay = true; ++ break; ++ } ++ } ++ return hasOverlay; ++} ++ + COverlay* CRenderer::Convert(CDVDOverlaySSA* o, double pts) + { + CRect src, dst; +diff --git a/xbmc/cores/VideoRenderers/OverlayRenderer.h b/xbmc/cores/VideoRenderers/OverlayRenderer.h +index 9b8e9da..ca02644 100644 +--- a/xbmc/cores/VideoRenderers/OverlayRenderer.h ++++ b/xbmc/cores/VideoRenderers/OverlayRenderer.h +@@ -100,6 +100,7 @@ namespace OVERLAY { + void Render(int idx); + void Flush(); + void Release(int idx); ++ bool HasOverlay(int idx); + + protected: + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index ab894ba..63bbdcc 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -120,6 +120,7 @@ CXBMCRenderManager::CXBMCRenderManager() + m_QueueSize = 2; + m_QueueSkip = 0; + m_format = RENDER_FMT_NONE; ++ m_renderedOverlay = false; + } + + CXBMCRenderManager::~CXBMCRenderManager() +@@ -233,7 +234,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + + /* make sure any queued frame was fully presented */ + XbmcThreads::EndTime endtime(5000); +- while(m_presentstep != PRESENT_IDLE) ++ while(m_presentstep != PRESENT_IDLE && m_presentstep != PRESENT_READY) + { + if(endtime.IsTimePast()) + { +@@ -292,6 +293,7 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi + m_presentpts = DVD_NOPTS_VALUE; + m_sleeptime = 1.0; + m_presentevent.notifyAll(); ++ m_renderedOverlay = false; + + CLog::Log(LOGDEBUG, "CXBMCRenderManager::Configure - %d", m_QueueSize); + } +@@ -766,22 +768,58 @@ void CXBMCRenderManager::RegisterRenderFeaturesCallBack(const void *ctx, RenderF + m_pRenderer->RegisterRenderFeaturesCallBack(ctx, fn); + } + +-void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha) ++void CXBMCRenderManager::Render(bool clear, DWORD flags, DWORD alpha, bool gui) + { + CSharedLock lock(m_sharedSection); + +- SPresent& m = m_Queue[m_presentsource]; ++ if (!gui && m_pRenderer->IsGuiLayer()) ++ return; + +- if( m.presentmethod == PRESENT_METHOD_BOB ) +- PresentFields(clear, flags, alpha); +- else if( m.presentmethod == PRESENT_METHOD_WEAVE ) +- PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha); +- else if( m.presentmethod == PRESENT_METHOD_BLEND ) +- PresentBlend(clear, flags, alpha); +- else +- PresentSingle(clear, flags, alpha); ++ if (!gui || m_pRenderer->IsGuiLayer()) ++ { ++ SPresent& m = m_Queue[m_presentsource]; ++ ++ if( m.presentmethod == PRESENT_METHOD_BOB ) ++ PresentFields(clear, flags, alpha); ++ else if( m.presentmethod == PRESENT_METHOD_WEAVE ) ++ PresentFields(clear, flags | RENDER_FLAG_WEAVE, alpha); ++ else if( m.presentmethod == PRESENT_METHOD_BLEND ) ++ PresentBlend(clear, flags, alpha); ++ else ++ PresentSingle(clear, flags, alpha); ++ } ++ ++ if (gui) ++ { ++ m_renderedOverlay = m_overlays.HasOverlay(m_presentsource); ++ m_overlays.Render(m_presentsource); ++ } ++} ++ ++bool CXBMCRenderManager::IsGuiLayer() ++{ ++ { CSingleLock lock(m_presentlock); ++ ++ if (!m_pRenderer) ++ return false; ++ ++ if (m_pRenderer->IsGuiLayer() || m_renderedOverlay || m_overlays.HasOverlay(m_presentsource)) ++ return true; ++ } ++ return false; ++} ++ ++bool CXBMCRenderManager::IsVideoLayer() ++{ ++ { CSingleLock lock(m_presentlock); + +- m_overlays.Render(m_presentsource); ++ if (!m_pRenderer) ++ return false; ++ ++ if (!m_pRenderer->IsGuiLayer()) ++ return true; ++ } ++ return false; + } + + /* simple present method */ +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 1086066..7280423 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -60,7 +60,9 @@ public: + void FrameMove(); + void FrameFinish(); + bool FrameWait(int ms); +- void Render(bool clear, DWORD flags = 0, DWORD alpha = 255); ++ void Render(bool clear, DWORD flags = 0, DWORD alpha = 255, bool gui = true); ++ bool IsGuiLayer(); ++ bool IsVideoLayer(); + void SetupScreenshot(); + + CRenderCapture* AllocRenderCapture(); +@@ -257,6 +259,7 @@ protected: + + + OVERLAY::CRenderer m_overlays; ++ bool m_renderedOverlay; + + void RenderCapture(CRenderCapture* capture); + void RemoveCapture(CRenderCapture* capture); +diff --git a/xbmc/guilib/GUIControl.h b/xbmc/guilib/GUIControl.h +index b303ccc..6e0b92e 100644 +--- a/xbmc/guilib/GUIControl.h ++++ b/xbmc/guilib/GUIControl.h +@@ -83,6 +83,9 @@ public: + virtual void Process(unsigned int currentTime, CDirtyRegionList &dirtyregions); + virtual void DoRender(); + virtual void Render() {}; ++ // Called after the actual rendering is completed to trigger additional ++ // non GUI rendering operations ++ virtual void RenderEx() {}; + + /*! \brief Returns whether or not we have processed */ + bool HasProcessed() const { return m_hasProcessed; }; +diff --git a/xbmc/guilib/GUIControlGroup.cpp b/xbmc/guilib/GUIControlGroup.cpp +index 7858e42..bdd7f54 100644 +--- a/xbmc/guilib/GUIControlGroup.cpp ++++ b/xbmc/guilib/GUIControlGroup.cpp +@@ -133,6 +133,13 @@ void CGUIControlGroup::Render() + g_graphicsContext.RestoreOrigin(); + } + ++void CGUIControlGroup::RenderEx() ++{ ++ for (iControls it = m_children.begin(); it != m_children.end(); ++it) ++ (*it)->RenderEx(); ++ CGUIControl::RenderEx(); ++} ++ + bool CGUIControlGroup::OnAction(const CAction &action) + { + ASSERT(false); // unimplemented +diff --git a/xbmc/guilib/GUIControlGroup.h b/xbmc/guilib/GUIControlGroup.h +index 054757f..0b38a56 100644 +--- a/xbmc/guilib/GUIControlGroup.h ++++ b/xbmc/guilib/GUIControlGroup.h +@@ -42,6 +42,7 @@ public: + + virtual void Process(unsigned int currentTime, CDirtyRegionList &dirtyregions); + virtual void Render(); ++ virtual void RenderEx(); + virtual bool OnAction(const CAction &action); + virtual bool OnMessage(CGUIMessage& message); + virtual bool SendControlMessage(CGUIMessage& message); +diff --git a/xbmc/guilib/GUIVideoControl.cpp b/xbmc/guilib/GUIVideoControl.cpp +index c47a6d5..126e95f 100644 +--- a/xbmc/guilib/GUIVideoControl.cpp ++++ b/xbmc/guilib/GUIVideoControl.cpp +@@ -42,8 +42,11 @@ CGUIVideoControl::~CGUIVideoControl(void) + + void CGUIVideoControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) + { ++ g_renderManager.FrameMove(); ++ + // TODO Proper processing which marks when its actually changed. Just mark always for now. +- MarkDirtyRegion(); ++ if (g_renderManager.IsGuiLayer()) ++ MarkDirtyRegion(); + + CGUIControl::Process(currentTime, dirtyregions); + } +@@ -67,14 +70,38 @@ void CGUIVideoControl::Render() + + #ifdef HAS_VIDEO_PLAYBACK + color_t alpha = g_graphicsContext.MergeAlpha(0xFF000000) >> 24; +- g_renderManager.Render(false, 0, alpha); ++ if (g_renderManager.IsVideoLayer()) ++ { ++ CRect old = g_graphicsContext.GetScissors(); ++ CRect region = GetRenderRegion(); ++ region.Intersect(old); ++ g_graphicsContext.BeginPaint(); ++ g_graphicsContext.SetScissors(region); ++ g_graphicsContext.Clear(0); ++ g_graphicsContext.SetScissors(old); ++ g_graphicsContext.EndPaint(); ++ } ++ else ++ g_renderManager.Render(false, 0, alpha); + #else + ((CDummyVideoPlayer *)g_application.m_pPlayer->GetInternal())->Render(); + #endif + } ++ // TODO: remove this crap: HAS_VIDEO_PLAYBACK ++ // instantiateing a vidio control having no playback is complete nonsense + CGUIControl::Render(); + } + ++void CGUIVideoControl::RenderEx() ++{ ++#ifdef HAS_VIDEO_PLAYBACK ++ if (g_application.m_pPlayer->IsPlayingVideo() && g_renderManager.IsStarted()) ++ g_renderManager.Render(false, 0, 255, false); ++ g_renderManager.FrameFinish(); ++#endif ++ CGUIControl::RenderEx(); ++} ++ + EVENT_RESULT CGUIVideoControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event) + { + if (!g_application.m_pPlayer->IsPlayingVideo()) return EVENT_RESULT_UNHANDLED; +diff --git a/xbmc/guilib/GUIVideoControl.h b/xbmc/guilib/GUIVideoControl.h +index a692d01..0f89a9a 100644 +--- a/xbmc/guilib/GUIVideoControl.h ++++ b/xbmc/guilib/GUIVideoControl.h +@@ -44,6 +44,7 @@ public: + + virtual void Process(unsigned int currentTime, CDirtyRegionList &dirtyregions); + virtual void Render(); ++ virtual void RenderEx(); + virtual EVENT_RESULT OnMouseEvent(const CPoint &point, const CMouseEvent &event); + virtual bool CanFocus() const; + virtual bool CanFocusFromPoint(const CPoint &point) const; +diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp +index 788bbe9..ef97251 100644 +--- a/xbmc/guilib/GUIWindowManager.cpp ++++ b/xbmc/guilib/GUIWindowManager.cpp +@@ -547,6 +547,24 @@ void CGUIWindowManager::RenderPass() const + } + } + ++void CGUIWindowManager::RenderEx() const ++{ ++ CGUIWindow* pWindow = GetWindow(GetActiveWindow()); ++ if (pWindow) ++ pWindow->RenderEx(); ++ ++ // We don't call RenderEx for now on dialogs since it is used ++ // to trigger non gui video rendering. We can activate it later at any time. ++ /* ++ vector &activeDialogs = m_activeDialogs; ++ for (iDialog it = activeDialogs.begin(); it != activeDialogs.end(); ++it) ++ { ++ if ((*it)->IsDialogRunning()) ++ (*it)->RenderEx(); ++ } ++ */ ++} ++ + bool CGUIWindowManager::Render() + { + assert(g_application.IsCurrentThread()); +@@ -586,13 +604,15 @@ bool CGUIWindowManager::Render() + if (g_advancedSettings.m_guiVisualizeDirtyRegions) + { + g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetResInfo(), false); +- const CDirtyRegionList &markedRegions = m_tracker.GetMarkedRegions(); ++ const CDirtyRegionList &markedRegions = m_tracker.GetMarkedRegions(); + for (CDirtyRegionList::const_iterator i = markedRegions.begin(); i != markedRegions.end(); ++i) + CGUITexture::DrawQuad(*i, 0x0fff0000); + for (CDirtyRegionList::const_iterator i = dirtyRegions.begin(); i != dirtyRegions.end(); ++i) + CGUITexture::DrawQuad(*i, 0x4c00ff00); + } + ++ RenderEx(); ++ + return hasRendered; + } + +diff --git a/xbmc/guilib/GUIWindowManager.h b/xbmc/guilib/GUIWindowManager.h +index 4f1f96f..ea7239a 100644 +--- a/xbmc/guilib/GUIWindowManager.h ++++ b/xbmc/guilib/GUIWindowManager.h +@@ -144,6 +144,7 @@ public: + #endif + private: + void RenderPass() const; ++ void RenderEx() const; + + void LoadNotOnDemandWindows(); + void UnloadNotOnDemandWindows(); +diff --git a/xbmc/video/windows/GUIWindowFullScreen.cpp b/xbmc/video/windows/GUIWindowFullScreen.cpp +index dfbf773..ed7c090 100644 +--- a/xbmc/video/windows/GUIWindowFullScreen.cpp ++++ b/xbmc/video/windows/GUIWindowFullScreen.cpp +@@ -353,6 +353,12 @@ bool CGUIWindowFullScreen::OnAction(const CAction &action) + return CGUIWindow::OnAction(action); + } + ++void CGUIWindowFullScreen::ClearBackground() ++{ ++ if (g_renderManager.IsVideoLayer()) ++ g_graphicsContext.Clear(0); ++} ++ + void CGUIWindowFullScreen::OnWindowLoaded() + { + CGUIWindow::OnWindowLoaded(); +@@ -455,6 +461,7 @@ bool CGUIWindowFullScreen::OnMessage(CGUIMessage& message) + #ifdef HAS_VIDEO_PLAYBACK + // make sure renderer is uptospeed + g_renderManager.Update(); ++ g_renderManager.FrameFinish(); + #endif + return true; + } +@@ -730,22 +737,40 @@ void CGUIWindowFullScreen::FrameMove() + SET_CONTROL_HIDDEN(BLUE_BAR); + SET_CONTROL_HIDDEN(CONTROL_GROUP_CHOOSER); + } ++ ++ g_renderManager.FrameMove(); + } + + void CGUIWindowFullScreen::Process(unsigned int currentTime, CDirtyRegionList &dirtyregion) + { ++ if (g_renderManager.IsGuiLayer()) ++ MarkDirtyRegion(); ++ ++ CGUIWindow::Process(currentTime, dirtyregion); ++ + // TODO: This isn't quite optimal - ideally we'd only be dirtying up the actual video render rect + // which is probably the job of the renderer as it can more easily track resizing etc. +- MarkDirtyRegion(); +- CGUIWindow::Process(currentTime, dirtyregion); + m_renderRegion.SetRect(0, 0, (float)g_graphicsContext.GetWidth(), (float)g_graphicsContext.GetHeight()); + } + + void CGUIWindowFullScreen::Render() + { ++ g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetVideoResolution(), false); ++ g_renderManager.Render(true, 0, 255); ++ g_graphicsContext.SetRenderingResolution(m_coordsRes, m_needsScaling); + CGUIWindow::Render(); + } + ++void CGUIWindowFullScreen::RenderEx() ++{ ++ CGUIWindow::RenderEx(); ++ g_graphicsContext.SetRenderingResolution(g_graphicsContext.GetVideoResolution(), false); ++#ifdef HAS_VIDEO_PLAYBACK ++ g_renderManager.Render(false, 0, 255, false); ++ g_renderManager.FrameFinish(); ++#endif ++} ++ + void CGUIWindowFullScreen::ChangetheTimeCode(int remote) + { + if (remote >= REMOTE_0 && remote <= REMOTE_9) +@@ -851,6 +876,8 @@ void CGUIWindowFullScreen::ToggleOSD() + else + pOSD->DoModal(); + } ++ ++ MarkDirtyRegion(); + } + + void CGUIWindowFullScreen::TriggerOSD() +diff --git a/xbmc/video/windows/GUIWindowFullScreen.h b/xbmc/video/windows/GUIWindowFullScreen.h +index 03608af..5a9b101 100644 +--- a/xbmc/video/windows/GUIWindowFullScreen.h ++++ b/xbmc/video/windows/GUIWindowFullScreen.h +@@ -30,9 +30,11 @@ public: + virtual ~CGUIWindowFullScreen(void); + virtual bool OnMessage(CGUIMessage& message); + virtual bool OnAction(const CAction &action); ++ virtual void ClearBackground(); + virtual void FrameMove(); + virtual void Process(unsigned int currentTime, CDirtyRegionList &dirtyregion); + virtual void Render(); ++ virtual void RenderEx(); + virtual void OnWindowLoaded(); + void ChangetheTimeCode(int remote); + void ChangetheTVGroup(bool next); +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-04-guilib-mark-control-dirty-when-setting-to-invisible.patch b/projects/imx6/patches/kodi/kodi-04-guilib-mark-control-dirty-when-setting-to-invisible.patch new file mode 100644 index 0000000000..dfaa34a512 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-04-guilib-mark-control-dirty-when-setting-to-invisible.patch @@ -0,0 +1,25 @@ +From 23ef73e82745569bcd95ce1fdbcc698318388b0f Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Mon, 5 Jan 2015 11:29:15 +0100 +Subject: [PATCH 4/6] guilib: mark control dirty when setting to invisible + +--- + xbmc/guilib/GUIControl.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/guilib/GUIControl.cpp b/xbmc/guilib/GUIControl.cpp +index e3d04db..ff2086b 100644 +--- a/xbmc/guilib/GUIControl.cpp ++++ b/xbmc/guilib/GUIControl.cpp +@@ -511,6 +511,8 @@ void CGUIControl::SetVisible(bool bVisible, bool setVisState) + { + m_forceHidden = !bVisible; + SetInvalid(); ++ if (m_forceHidden) ++ MarkDirtyRegion(); + } + if (m_forceHidden) + { // reset any visible animations that are in process +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-05-renderer-exit-gfx-lock-when-waiting-for-present-time.patch b/projects/imx6/patches/kodi/kodi-05-renderer-exit-gfx-lock-when-waiting-for-present-time.patch new file mode 100644 index 0000000000..c528ad3ca3 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-05-renderer-exit-gfx-lock-when-waiting-for-present-time.patch @@ -0,0 +1,27 @@ +From ef6230c3d3106f045719cdebf3ca33cc5cedf88d Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Tue, 6 Jan 2015 13:13:27 +0100 +Subject: [PATCH 5/6] renderer: exit gfx lock when waiting for present time + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 63bbdcc..b394d7b 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -381,7 +381,10 @@ void CXBMCRenderManager::FrameFinish() + SPresent& m = m_Queue[m_presentsource]; + + if(g_graphicsContext.IsFullScreenVideo()) ++ { ++ CSingleExit lock(g_graphicsContext); + WaitPresentTime(m.timestamp); ++ } + + m_clock_framefinish = GetPresentTime(); + +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-05-rfix-sequence-from-WaitFrame-Render-FrameMov.patch b/projects/imx6/patches/kodi/kodi-05-rfix-sequence-from-WaitFrame-Render-FrameMov.patch new file mode 100644 index 0000000000..0cd656b49e --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-05-rfix-sequence-from-WaitFrame-Render-FrameMov.patch @@ -0,0 +1,94 @@ +From ecf0df3917462187b6def084bb7e3adf797effcd Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Fri, 23 Jan 2015 07:41:46 +0100 +Subject: [PATCH] renderer: fix sequence from WaitFrame, Render, FrameMove to + WaitFrame, FrameMove, Render + +--- + xbmc/Application.cpp | 12 +++++++++--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++++++++++-- + xbmc/cores/VideoRenderers/RenderManager.h | 3 ++- + 3 files changed, 21 insertions(+), 6 deletions(-) + +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index fe44706..3410209 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2212,16 +2212,17 @@ void CApplication::Render() + bool limitFrames = false; + unsigned int singleFrameTime = 10; // default limit 100 fps + ++ // Whether externalplayer is playing and we're unfocused ++ bool extPlayerActive = m_pPlayer->GetCurrentPlayer() == EPC_EXTPLAYER && m_pPlayer->IsPlaying() && !m_AppFocused; ++ + { + // Less fps in DPMS + bool lowfps = m_dpmsIsActive || g_Windowing.EnableFrameLimiter(); +- // Whether externalplayer is playing and we're unfocused +- bool extPlayerActive = m_pPlayer->GetCurrentPlayer() == EPC_EXTPLAYER && m_pPlayer->IsPlaying() && !m_AppFocused; + + m_bPresentFrame = false; + if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback()) + { +- m_bPresentFrame = g_renderManager.FrameWait(100); ++ m_bPresentFrame = g_renderManager.HasFrame(); + } + else + { +@@ -2322,6 +2323,11 @@ void CApplication::Render() + if (flip) + g_graphicsContext.Flip(dirtyRegions); + ++ if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback()) ++ { ++ g_renderManager.FrameWait(100); ++ } ++ + m_lastFrameTime = XbmcThreads::SystemClockMillis(); + CTimeUtils::UpdateFrameTime(flip); + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 72ad819..85c3565 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -316,13 +316,21 @@ void CXBMCRenderManager::Update() + m_pRenderer->Update(); + } + +-bool CXBMCRenderManager::FrameWait(int ms) ++void CXBMCRenderManager::FrameWait(int ms) + { + XbmcThreads::EndTime timeout(ms); + CSingleLock lock(m_presentlock); + while(m_presentstep == PRESENT_IDLE && !timeout.IsTimePast()) + m_presentevent.wait(lock, timeout.MillisLeft()); +- return m_presentstep != PRESENT_IDLE; ++} ++ ++bool CXBMCRenderManager::HasFrame() ++{ ++ CSingleLock lock(m_presentlock); ++ if (m_presentstep == PRESENT_FRAME || m_presentstep == PRESENT_FRAME2) ++ return true; ++ else ++ return false; + } + + void CXBMCRenderManager::FrameMove() +diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h +index 7280423..b80319a 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.h ++++ b/xbmc/cores/VideoRenderers/RenderManager.h +@@ -59,7 +59,8 @@ public: + void Update(); + void FrameMove(); + void FrameFinish(); +- bool FrameWait(int ms); ++ void FrameWait(int ms); ++ bool HasFrame(); + void Render(bool clear, DWORD flags = 0, DWORD alpha = 255, bool gui = true); + bool IsGuiLayer(); + bool IsVideoLayer(); +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-06-imx-Rework-of-frame-processing-and-rendering-based-o.patch b/projects/imx6/patches/kodi/kodi-06-imx-Rework-of-frame-processing-and-rendering-based-o.patch new file mode 100644 index 0000000000..f36a721288 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-06-imx-Rework-of-frame-processing-and-rendering-based-o.patch @@ -0,0 +1,2593 @@ +From b71b5abc387c6d3feda9c1a6dadb1f565dfb15e1 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Thu, 22 Jan 2015 10:15:38 +0100 +Subject: [PATCH 6/6] [imx] Rework of frame processing and rendering based on + fullscreen PR + +Conflicts: + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +--- + language/English/strings.po | 14 +- + xbmc/Application.cpp | 34 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 144 ++- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 3 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 12 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1102 +++++++++++++++++--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 336 ++++-- + xbmc/guilib/GUIVideoControl.cpp | 4 + + xbmc/guilib/GUIWindow.h | 2 +- + xbmc/guilib/GUIWindowManager.cpp | 2 +- + xbmc/settings/VideoSettings.h | 3 + + xbmc/utils/Screenshot.cpp | 13 +- + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 + + xbmc/video/windows/GUIWindowFullScreen.cpp | 6 +- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 70 +- + xbmc/windowing/egl/WinSystemEGL.cpp | 9 +- + 16 files changed, 1453 insertions(+), 303 deletions(-) + +diff --git a/language/English/strings.po b/language/English/strings.po +index 15090fc..d994570 100755 +--- a/language/English/strings.po ++++ b/language/English/strings.po +@@ -7548,7 +7548,19 @@ msgctxt "#16333" + msgid "MMAL - Bob (Half)" + msgstr "" + +-#empty strings from id 16334 to 16399 ++#. Description of OSD video settings for deinterlace method with label #16334 ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16334" ++msgid "IMX - Fast motion" ++msgstr "" ++ ++#. Description of OSD video settings for deinterlace method with label #16335 ++#: xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++msgctxt "#16335" ++msgid "IMX - Fast motion (Double)" ++msgstr "" ++ ++#empty strings from id 16336 to 16399 + + #: xbmc/video/dialogs/GUIDialogVideoSettings.cpp + msgctxt "#16400" +diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp +index 137872c..fe44706 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -706,7 +706,7 @@ bool CApplication::Create() + CLog::Log(LOGNOTICE, "WARNING: unsupported ffmpeg version detected"); + } + #endif +- ++ + std::string cpuModel(g_cpuInfo.getCPUModel()); + if (!cpuModel.empty()) + CLog::Log(LOGNOTICE, "Host CPU: %s, %d core%s available", cpuModel.c_str(), g_cpuInfo.getCPUCount(), (g_cpuInfo.getCPUCount() == 1) ? "" : "s"); +@@ -1407,7 +1407,7 @@ bool CApplication::Initialize() + + g_windowManager.Add(new CGUIDialogPeripheralManager); + g_windowManager.Add(new CGUIDialogPeripheralSettings); +- ++ + g_windowManager.Add(new CGUIDialogMediaFilter); + g_windowManager.Add(new CGUIDialogSubtitles); + +@@ -1811,7 +1811,7 @@ bool CApplication::OnSettingUpdate(CSetting* &setting, const char *oldSettingId, + CSettingString *audioDevice = (CSettingString*)setting; + // Gotham and older didn't enumerate audio devices per stream on osx + // add stream0 per default which should be ok for all old settings. +- if (!StringUtils::EqualsNoCase(audioDevice->GetValue(), "DARWINOSX:default") && ++ if (!StringUtils::EqualsNoCase(audioDevice->GetValue(), "DARWINOSX:default") && + StringUtils::FindWords(audioDevice->GetValue().c_str(), ":stream") == std::string::npos) + { + std::string newSetting = audioDevice->GetValue(); +@@ -2538,8 +2538,8 @@ bool CApplication::OnAction(const CAction &action) + if (action.IsMouse()) + g_Mouse.SetActive(true); + +- +- if (action.GetID() == ACTION_CREATE_EPISODE_BOOKMARK) ++ ++ if (action.GetID() == ACTION_CREATE_EPISODE_BOOKMARK) + { + CGUIDialogVideoBookmarks::OnAddEpisodeBookmark(); + } +@@ -2547,7 +2547,7 @@ bool CApplication::OnAction(const CAction &action) + { + CGUIDialogVideoBookmarks::OnAddBookmark(); + } +- ++ + // The action PLAYPAUSE behaves as ACTION_PAUSE if we are currently + // playing or ACTION_PLAYER_PLAY if we are seeking (FF/RW) or not playing. + if (action.GetID() == ACTION_PLAYER_PLAYPAUSE) +@@ -3447,7 +3447,7 @@ bool CApplication::Cleanup() + #ifdef HAS_DVD_DRIVE + CLibcdio::ReleaseInstance(); + #endif +-#endif ++#endif + #if defined(TARGET_ANDROID) + // enable for all platforms once it's safe + g_sectionLoader.UnloadAll(); +@@ -3729,7 +3729,7 @@ PlayBackRet CApplication::PlayStack(const CFileItem& item, bool bRestart) + else + { + LoadVideoSettings(item.GetPath()); +- ++ + // see if we have the info in the database + // TODO: If user changes the time speed (FPS via framerate conversion stuff) + // then these times will be wrong. +@@ -4034,7 +4034,7 @@ PlayBackRet CApplication::PlayFile(const CFileItem& item, bool bRestart) + CSingleLock lock(m_playStateMutex); + // tell system we are starting a file + m_bPlaybackStarting = true; +- ++ + // for playing a new item, previous playing item's callback may already + // pushed some delay message into the threadmessage list, they are not + // expected be processed after or during the new item playback starting. +@@ -4344,7 +4344,7 @@ void CApplication::SaveFileState(bool bForeground /* = false */) + m_progressTrackingVideoResumeBookmark, + m_progressTrackingPlayCountUpdate, + CMediaSettings::Get().GetCurrentVideoSettings()); +- ++ + if (bForeground) + { + // Run job in the foreground to make sure it finishes +@@ -4437,11 +4437,11 @@ void CApplication::LoadVideoSettings(const std::string &path) + if (dbs.Open()) + { + CLog::Log(LOGDEBUG, "Loading settings for %s", path.c_str()); +- ++ + // Load stored settings if they exist, otherwise use default + if (!dbs.GetVideoSettings(path, CMediaSettings::Get().GetCurrentVideoSettings())) + CMediaSettings::Get().GetCurrentVideoSettings() = CMediaSettings::Get().GetDefaultVideoSettings(); +- ++ + dbs.Close(); + } + } +@@ -4762,7 +4762,7 @@ bool CApplication::OnMessage(CGUIMessage& message) + + // Update our infoManager with the new details etc. + if (m_nextPlaylistItem >= 0) +- { ++ { + // playing an item which is not in the list - player might be stopped already + // so do nothing + if (playList.size() <= m_nextPlaylistItem) +@@ -5364,7 +5364,7 @@ float CApplication::GetVolume(bool percentage /* = true */) const + // converts the hardware volume to a percentage + return m_volumeLevel * 100.0f; + } +- ++ + return m_volumeLevel; + } + +@@ -5839,15 +5839,15 @@ void CApplication::CloseNetworkShares() + #if defined(HAS_FILESYSTEM_SMB) && !defined(TARGET_WINDOWS) + smb.Deinit(); + #endif +- ++ + #ifdef HAS_FILESYSTEM_NFS + gNfsConnection.Deinit(); + #endif +- ++ + #ifdef HAS_FILESYSTEM_AFP + gAfpConnection.Deinit(); + #endif +- ++ + #ifdef HAS_FILESYSTEM_SFTP + CSFTPSessionManager::DisconnectAllSessions(); + #endif +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index a765461..74e950c 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -89,7 +89,12 @@ static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR; + #include "windowing/egl/EGLWrapper.h" + #include "DVDCodecs/Video/DVDVideoCodecIMX.h" + ++#define GL_VIV_YV12 0x8FC0 + #define GL_VIV_NV12 0x8FC1 ++#define GL_VIV_YUY2 0x8FC2 ++#define GL_VIV_UYVY 0x8FC3 ++#define GL_VIV_NV21 0x8FC4 ++#define GL_VIV_I420 0x8FC5 + typedef void (GL_APIENTRYP PFNGLTEXDIRECTVIVMAPPROC) (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical); + typedef void (GL_APIENTRYP PFNGLTEXDIRECTINVALIDATEVIVPROC) (GLenum Target); + static PFNGLTEXDIRECTVIVMAPPROC glTexDirectVIVMap; +@@ -608,6 +613,69 @@ void CLinuxRendererGLES::RenderUpdateVideo(bool clear, DWORD flags, DWORD alpha) + + return; + } ++#ifdef HAS_IMXVPU ++ else if (m_renderMethod & RENDER_IMXMAP) ++ { ++ ManageDisplay(); ++ ++ CDVDVideoCodecIMXBuffer *buffer = m_buffers[m_iYV12RenderBuffer].IMXBuffer; ++ if (buffer != NULL && buffer->IsValid()) ++ { ++ g_IMXContext.SetBlitRects(m_sourceRect, m_destRect); ++ ++ bool topFieldFirst = true; ++ bool done = true; ++ ++ // Deinterlacing requested ++ if (flags & RENDER_FLAG_FIELDMASK) ++ { ++ if (flags & RENDER_FLAG_FIELD0) ++ { ++ // Double rate first frame ++ topFieldFirst = flags & RENDER_FLAG_TOP; ++ g_IMXContext.SetDeInterlacing(true); ++ g_IMXContext.SetDoubleRate(true); ++ g_IMXContext.SetInterpolatedFrame(true); ++ done = false; ++ } ++ else if (flags & RENDER_FLAG_FIELD1) ++ { ++ // Double rate second frame ++ // FIELD1 swaps the render field order, we need to ++ // swap it back for the IPU ++ topFieldFirst = flags & RENDER_FLAG_BOT; ++ g_IMXContext.SetDeInterlacing(true); ++ g_IMXContext.SetDoubleRate(true); ++ g_IMXContext.SetInterpolatedFrame(false); ++ } ++ else ++ { ++ // Fast motion ++ topFieldFirst = flags & RENDER_FLAG_TOP; ++ g_IMXContext.SetDeInterlacing(true); ++ g_IMXContext.SetDoubleRate(false); ++ } ++ } ++ // Progressive ++ else ++ g_IMXContext.SetDeInterlacing(false); ++ ++#if 0 ++ int page = g_IMXContext.GetCurrentPage(); ++ page = 1-page; ++ ++ g_IMXContext.Blit(page, NULL, buffer, topFieldFirst); ++ g_IMXContext.ShowPage(page); ++#else ++ g_IMXContext.BlitAsync(NULL, buffer, topFieldFirst); ++#endif ++ ++ // Prevent rendering again ++ if (done) ++ SAFE_RELEASE(m_buffers[m_iYV12RenderBuffer].IMXBuffer); ++ } ++ } ++#endif + } + + void CLinuxRendererGLES::FlipPage(int source) +@@ -618,7 +686,6 @@ void CLinuxRendererGLES::FlipPage(int source) + m_iYV12RenderBuffer = NextYV12Texture(); + + m_buffers[m_iYV12RenderBuffer].flipindex = ++m_flipindex; +- + return; + } + +@@ -963,13 +1030,7 @@ void CLinuxRendererGLES::ReleaseBuffer(int idx) + #endif + #ifdef HAS_IMXVPU + if (m_renderMethod & RENDER_IMXMAP) +- { +- if (buf.IMXBuffer) +- { +- SAFE_RELEASE(buf.IMXBuffer); +- buf.IMXBuffer = NULL; +- } +- } ++ SAFE_RELEASE(buf.IMXBuffer); + #endif + } + +@@ -1241,7 +1302,7 @@ void CLinuxRendererGLES::RenderMultiPass(int index, int field) + // imgwidth *= planes[0].pixpertex_x; + // imgheight *= planes[0].pixpertex_y; + // } +-// ++// + // glBegin(GL_QUADS); + // + // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1); +@@ -1679,6 +1740,7 @@ void CLinuxRendererGLES::RenderCoreVideoRef(int index, int field) + + void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) + { ++#if 0 + #if defined(HAS_IMXVPU) + #ifdef DEBUG_VERBOSE + unsigned int time = XbmcThreads::SystemClockMillis(); +@@ -1754,6 +1816,7 @@ void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) + CLog::Log(LOGDEBUG, "RenderIMXMAPTexture %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time); + #endif + #endif ++#endif + } + + bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture) +@@ -2717,42 +2780,6 @@ void CLinuxRendererGLES::SetTextureFilter(GLenum method) + //******************************************************************************************************** + void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + { +-#ifdef HAS_IMXVPU +- YUVBUFFER& buf = m_buffers[index]; +- CDVDVideoCodecIMXBuffer* IMXBuffer = buf.IMXBuffer; +- +- if(IMXBuffer) +- { +- CDVDVideoCodecIMX::Enter(); +- +- if(!IMXBuffer->IsValid()) +- { +- CDVDVideoCodecIMX::Leave(); +- return; +- } +- +- YUVPLANE &plane = m_buffers[index].fields[0][0]; +- +- glActiveTexture(GL_TEXTURE0); +- glBindTexture(m_textureTarget, plane.id); +- +- GLuint physical = ~0U; +- GLvoid *virt = (GLvoid*)IMXBuffer->m_VirtAddr; +- glTexDirectVIVMap(m_textureTarget, IMXBuffer->m_iWidth, IMXBuffer->m_iHeight, GL_VIV_NV12, +- (GLvoid **)&virt, &physical); +- glTexDirectInvalidateVIV(m_textureTarget); +- +- glBindTexture(m_textureTarget, 0); +- +- plane.flipindex = m_buffers[index].flipindex; +- plane.texwidth = IMXBuffer->m_iWidth; +- plane.texheight = IMXBuffer->m_iHeight; +- +- CalculateTextureSourceRects(index, 1); +- +- CDVDVideoCodecIMX::Leave(); +- } +-#endif + } + + void CLinuxRendererGLES::DeleteIMXMAPTexture(int index) +@@ -2868,9 +2895,6 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode) + if(m_renderMethod & RENDER_CVREF) + return false; + +- if(m_renderMethod & RENDER_IMXMAP) +- return false; +- + if(mode == VS_DEINTERLACEMODE_AUTO + || mode == VS_DEINTERLACEMODE_FORCE) + return true; +@@ -2899,13 +2923,19 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) + if(m_renderMethod & RENDER_CVREF) + return false; + +- if(m_renderMethod & RENDER_IMXMAP) +- return false; +- + if(method == VS_INTERLACEMETHOD_AUTO) + return true; + +-#if defined(__i386__) || defined(__x86_64__) ++ if(m_renderMethod & RENDER_IMXMAP) ++ { ++ if(method == VS_INTERLACEMETHOD_IMX_FASTMOTION ++ || method == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE) ++ return true; ++ else ++ return false; ++ } ++ ++#if !defined(TARGET_ANDROID) && (defined(__i386__) || defined(__x86_64__)) + if(method == VS_INTERLACEMETHOD_DEINTERLACE + || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF + || method == VS_INTERLACEMETHOD_SW_BLEND) +@@ -2926,6 +2956,9 @@ bool CLinuxRendererGLES::Supports(ESCALINGMETHOD method) + return itr != m_scalingMethods.end(); + } + ++ if(m_renderMethod & RENDER_IMXMAP) ++ return false; ++ + if(method == VS_SCALINGMETHOD_NEAREST + || method == VS_SCALINGMETHOD_LINEAR) + return true; +@@ -2954,7 +2987,7 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() + return VS_INTERLACEMETHOD_NONE; + + if(m_renderMethod & RENDER_IMXMAP) +- return VS_INTERLACEMETHOD_NONE; ++ return VS_INTERLACEMETHOD_IMX_FASTMOTION; + + #if defined(__i386__) || defined(__x86_64__) + return VS_INTERLACEMETHOD_DEINTERLACE_HALF; +@@ -2970,6 +3003,9 @@ unsigned int CLinuxRendererGLES::GetOptimalBufferSize() + m_format == RENDER_FMT_EGLIMG || + m_format == RENDER_FMT_MEDIACODEC) + return 2; ++ else if(m_format == RENDER_FMT_IMXMAP) ++ // Let the codec control the buffer size ++ return GetMaxBufferSize(); + else + return 3; + } +@@ -3061,7 +3097,7 @@ void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecIMXBuffer *buffer, int index + + bool CLinuxRendererGLES::IsGuiLayer() + { +- if (m_format == RENDER_FMT_BYPASS) ++ if (m_format == RENDER_FMT_BYPASS || m_format == RENDER_FMT_IMXMAP) + return false; + else + return true; +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index b865033..ce5356d 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -42,6 +42,9 @@ namespace Shaders { class BaseVideoFilterShader; } + class COpenMaxVideo; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; ++#ifdef HAS_IMXVPU ++class CDVDVideoCodecIMXBuffer; ++#endif + typedef std::vector Features; + + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index b394d7b..72ad819 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -668,7 +668,10 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + deinterlacemode = VS_DEINTERLACEMODE_OFF; + + if (deinterlacemode == VS_DEINTERLACEMODE_OFF) ++ { + presentmethod = PRESENT_METHOD_SINGLE; ++ sync = FS_NONE; ++ } + else + { + if (deinterlacemode == VS_DEINTERLACEMODE_AUTO && sync == FS_NONE) +@@ -683,6 +686,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L + else if (interlacemethod == VS_INTERLACEMETHOD_RENDER_BOB_INVERTED) { presentmethod = PRESENT_METHOD_BOB; invert = true; } + else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BOB) presentmethod = PRESENT_METHOD_BOB; + else if (interlacemethod == VS_INTERLACEMETHOD_DXVA_BEST) presentmethod = PRESENT_METHOD_BOB; ++ else if (interlacemethod == VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE) presentmethod = PRESENT_METHOD_BOB; + else presentmethod = PRESENT_METHOD_SINGLE; + + /* default to odd field if we want to deinterlace and don't know better */ +@@ -829,8 +833,14 @@ bool CXBMCRenderManager::IsVideoLayer() + void CXBMCRenderManager::PresentSingle(bool clear, DWORD flags, DWORD alpha) + { + CSingleLock lock(g_graphicsContext); ++ SPresent& m = m_Queue[m_presentsource]; + +- m_pRenderer->RenderUpdate(clear, flags, alpha); ++ if (m.presentfield == FS_BOT) ++ m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_BOT, alpha); ++ else if (m.presentfield == FS_TOP) ++ m_pRenderer->RenderUpdate(clear, flags | RENDER_FLAG_TOP, alpha); ++ else ++ m_pRenderer->RenderUpdate(clear, flags, alpha); + } + + /* new simpler method of handling interlaced material, * +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index ca0abcc..a4d3c7e 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -20,25 +20,34 @@ + + #include "DVDVideoCodecIMX.h" + +-#include +-#include +-#include +-#include +-#include +-#include ++#include "settings/AdvancedSettings.h" + #include "threads/SingleLock.h" ++#include "threads/Atomics.h" + #include "utils/log.h" + #include "DVDClock.h" +-#include "settings/AdvancedSettings.h" +-#include "threads/Atomics.h" + ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define IMX_VDI_MAX_WIDTH 968 + #define FRAME_ALIGN 16 + #define MEDIAINFO 1 ++#define RENDER_QUEUE_SIZE 3 + #define _4CC(c1,c2,c3,c4) (((uint32_t)(c4)<<24)|((uint32_t)(c3)<<16)|((uint32_t)(c2)<<8)|(uint32_t)(c1)) + #define Align(ptr,align) (((unsigned int)ptr + (align) - 1)/(align)*(align)) ++#define Align2(ptr,align) (((unsigned int)ptr)/(align)*(align)) ++ ++ ++// Global instance ++CIMXContext g_IMXContext; ++ + + // Experiments show that we need at least one more (+1) VPU buffer than the min value returned by the VPU +-const int CDVDVideoCodecIMX::m_extraVpuBuffers = 6; ++const int CDVDVideoCodecIMX::m_extraVpuBuffers = 1+RENDER_QUEUE_SIZE+2; + const int CDVDVideoCodecIMX::m_maxVpuDecodeLoops = 5; + CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock; + +@@ -90,8 +99,8 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + return true; + + AllocFailure: +- VpuFreeBuffers(); +- return false; ++ VpuFreeBuffers(); ++ return false; + } + + int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr) +@@ -104,7 +113,7 @@ int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr) + return -1; + } + +-bool CDVDVideoCodecIMX::VpuFreeBuffers(void) ++bool CDVDVideoCodecIMX::VpuFreeBuffers() + { + VpuMemDesc vpuMem; + VpuDecRetCode vpuRet; +@@ -135,7 +144,7 @@ bool CDVDVideoCodecIMX::VpuFreeBuffers(void) + vpuRet = VPU_DecFreeMem(&vpuMem); + if(vpuRet != VPU_DEC_RET_SUCCESS) + { +- CLog::Log(LOGERROR, "%s - Errror while trying to free physical memory (%d).\n", __FUNCTION__, ret); ++ CLog::Log(LOGERROR, "%s - Error while trying to free physical memory (%d).\n", __FUNCTION__, ret); + ret = false; + } + } +@@ -148,7 +157,7 @@ bool CDVDVideoCodecIMX::VpuFreeBuffers(void) + } + + +-bool CDVDVideoCodecIMX::VpuOpen(void) ++bool CDVDVideoCodecIMX::VpuOpen() + { + VpuDecRetCode ret; + VpuVersionInfo vpuVersion; +@@ -185,7 +194,11 @@ bool CDVDVideoCodecIMX::VpuOpen(void) + VpuAllocBuffers(&memInfo); + + m_decOpenParam.nReorderEnable = 1; ++#ifdef IMX_INPUT_FORMAT_I420 ++ m_decOpenParam.nChromaInterleave = 0; ++#else + m_decOpenParam.nChromaInterleave = 1; ++#endif + m_decOpenParam.nMapType = 0; + m_decOpenParam.nTiled2LinearEnable = 0; + m_decOpenParam.nEnableFileMode = 0; +@@ -206,6 +219,24 @@ bool CDVDVideoCodecIMX::VpuOpen(void) + goto VpuOpenError; + } + ++ config = VPU_DEC_CONF_BUFDELAY; ++ param = 0; ++ ret = VPU_DecConfig(m_vpuHandle, config, ¶m); ++ if (ret != VPU_DEC_RET_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s - iMX VPU set buffer delay failed (%d).\n", __FUNCTION__, ret); ++ goto VpuOpenError; ++ } ++ ++ config = VPU_DEC_CONF_INPUTTYPE; ++ param = VPU_DEC_IN_NORMAL; ++ ret = VPU_DecConfig(m_vpuHandle, config, ¶m); ++ if (ret != VPU_DEC_RET_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s - iMX VPU configure input type failed (%d).\n", __FUNCTION__, ret); ++ goto VpuOpenError; ++ } ++ + // Note that libvpufsl (file vpu_wrapper.c) associates VPU_DEC_CAP_FRAMESIZE + // capability to the value of nDecFrameRptEnabled which is in fact directly + // related to the ability to generate VPU_DEC_ONE_FRM_CONSUMED even if the +@@ -225,52 +256,78 @@ VpuOpenError: + return false; + } + +-bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) ++bool CDVDVideoCodecIMX::VpuAllocFrameBuffers() + { ++ int totalSize = 0; ++ int ySize = 0; ++ int uSize = 0; ++ int vSize = 0; ++ int mvSize = 0; ++ int yStride = 0; ++ int uvStride = 0; ++ + VpuDecRetCode ret; + VpuMemDesc vpuMem; +- int totalSize=0; +- int mvSize=0; +- int ySize=0; +- int uvSize=0; +- int yStride=0; +- int uvStride=0; + unsigned char* ptr; + unsigned char* ptrVirt; + int nAlign; + +- m_vpuFrameBufferNum = m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers; ++ m_vpuFrameBufferNum = m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers; + m_vpuFrameBuffers = new VpuFrameBuffer[m_vpuFrameBufferNum]; + +- yStride=Align(m_initInfo.nPicWidth,FRAME_ALIGN); ++ yStride = Align(m_initInfo.nPicWidth,FRAME_ALIGN); + if(m_initInfo.nInterlace) + { +- ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,(2*FRAME_ALIGN)); ++ ySize = Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,(2*FRAME_ALIGN)); + } + else + { +- ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN); ++ ySize = Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN); + } + +- //NV12 for all video +- uvStride=yStride; +- uvSize=ySize/2; +- mvSize=uvSize/2; ++#ifdef IMX_INPUT_FORMAT_I420 ++ switch (m_initInfo.nMjpgSourceFormat) ++ { ++ case 0: // I420 (4:2:0) ++ uvStride = yStride / 2; ++ uSize = vSize = mvSize = ySize / 4; ++ break; ++ case 1: // Y42B (4:2:2 horizontal) ++ uvStride = yStride / 2; ++ uSize = vSize = mvSize = ySize / 2; ++ break; ++ case 3: // Y444 (4:4:4) ++ uvStride = yStride; ++ uSize = vSize = mvSize = ySize; ++ break; ++ default: ++ CLog::Log(LOGERROR, "%s: invalid source format in init info\n",__FUNCTION__,ret); ++ return false; ++ } ++ ++#else ++ // NV12 ++ uvStride = yStride; ++ uSize = ySize/2; ++ mvSize = uSize/2; ++#endif + +- nAlign=m_initInfo.nAddressAlignment; ++ nAlign = m_initInfo.nAddressAlignment; + if(nAlign>1) + { +- ySize=Align(ySize,nAlign); +- uvSize=Align(uvSize,nAlign); ++ ySize = Align(ySize, nAlign); ++ uSize = Align(uSize, nAlign); ++ vSize = Align(vSize, nAlign); ++ mvSize = Align(mvSize, nAlign); + } + +- m_outputBuffers = new CDVDVideoCodecIMXBuffer*[m_vpuFrameBufferNum]; ++ m_outputBuffers = new CDVDVideoCodecIMXVPUBuffer*[m_vpuFrameBufferNum]; + + for (int i=0 ; i < m_vpuFrameBufferNum; i++) + { +- totalSize=(ySize+uvSize+mvSize+nAlign)*1; ++ totalSize = ySize + uSize + vSize + mvSize + nAlign; + +- vpuMem.nSize=totalSize; ++ vpuMem.nSize = totalSize; + ret = VPU_DecGetMem(&vpuMem); + if(ret != VPU_DEC_RET_SUCCESS) + { +@@ -287,42 +344,52 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nSize = vpuMem.nSize; + + //fill frameBuf +- ptr=(unsigned char*)vpuMem.nPhyAddr; +- ptrVirt=(unsigned char*)vpuMem.nVirtAddr; ++ ptr = (unsigned char*)vpuMem.nPhyAddr; ++ ptrVirt = (unsigned char*)vpuMem.nVirtAddr; + + //align the base address + if(nAlign>1) + { +- ptr=(unsigned char*)Align(ptr,nAlign); +- ptrVirt=(unsigned char*)Align(ptrVirt,nAlign); ++ ptr = (unsigned char*)Align(ptr,nAlign); ++ ptrVirt = (unsigned char*)Align(ptrVirt,nAlign); + } + + // fill stride info +- m_vpuFrameBuffers[i].nStrideY=yStride; +- m_vpuFrameBuffers[i].nStrideC=uvStride; ++ m_vpuFrameBuffers[i].nStrideY = yStride; ++ m_vpuFrameBuffers[i].nStrideC = uvStride; + + // fill phy addr +- m_vpuFrameBuffers[i].pbufY=ptr; +- m_vpuFrameBuffers[i].pbufCb=ptr+ySize; +- m_vpuFrameBuffers[i].pbufCr=0; +- m_vpuFrameBuffers[i].pbufMvCol=ptr+ySize+uvSize; ++ m_vpuFrameBuffers[i].pbufY = ptr; ++ m_vpuFrameBuffers[i].pbufCb = ptr + ySize; ++#ifdef IMX_INPUT_FORMAT_I420 ++ m_vpuFrameBuffers[i].pbufCr = ptr + ySize + uSize; ++#else ++ m_vpuFrameBuffers[i].pbufCr = 0; ++#endif ++ m_vpuFrameBuffers[i].pbufMvCol = ptr + ySize + uSize + vSize; + + // fill virt addr +- m_vpuFrameBuffers[i].pbufVirtY=ptrVirt; +- m_vpuFrameBuffers[i].pbufVirtCb=ptrVirt+ySize; +- m_vpuFrameBuffers[i].pbufVirtCr=0; +- m_vpuFrameBuffers[i].pbufVirtMvCol=ptrVirt+ySize+uvSize; ++ m_vpuFrameBuffers[i].pbufVirtY = ptrVirt; ++ m_vpuFrameBuffers[i].pbufVirtCb = ptrVirt + ySize; ++#ifdef IMX_INPUT_FORMAT_I420 ++ m_vpuFrameBuffers[i].pbufVirtCr = ptrVirt + ySize + uSize; ++#else ++ m_vpuFrameBuffers[i].pbufVirtCr = 0; ++#endif ++ m_vpuFrameBuffers[i].pbufVirtMvCol = ptrVirt + ySize + uSize + vSize; + +- m_vpuFrameBuffers[i].pbufY_tilebot=0; +- m_vpuFrameBuffers[i].pbufCb_tilebot=0; +- m_vpuFrameBuffers[i].pbufVirtY_tilebot=0; +- m_vpuFrameBuffers[i].pbufVirtCb_tilebot=0; ++ m_vpuFrameBuffers[i].pbufY_tilebot = 0; ++ m_vpuFrameBuffers[i].pbufCb_tilebot = 0; ++ m_vpuFrameBuffers[i].pbufVirtY_tilebot = 0; ++ m_vpuFrameBuffers[i].pbufVirtCb_tilebot = 0; + + #ifdef TRACE_FRAMES +- m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(i); ++ m_outputBuffers[i] = new CDVDVideoCodecIMXVPUBuffer(i); + #else +- m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(); ++ m_outputBuffers[i] = new CDVDVideoCodecIMXVPUBuffer; + #endif ++ // Those buffers are ours so lock them to prevent destruction ++ m_outputBuffers[i]->Lock(); + } + + return true; +@@ -335,6 +402,7 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + m_vpuFrameBuffers = NULL; + m_outputBuffers = NULL; + m_lastBuffer = NULL; ++ m_currentBuffer = NULL; + m_extraMem = NULL; + m_vpuFrameBufferNum = 0; + m_dropState = false; +@@ -349,6 +417,9 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + m_convert_bitstream = false; + m_bytesToBeConsumed = 0; + m_previousPts = DVD_NOPTS_VALUE; ++#ifdef DUMP_STREAM ++ m_dump = NULL; ++#endif + } + + CDVDVideoCodecIMX::~CDVDVideoCodecIMX() +@@ -364,6 +435,26 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + return false; + } + ++ if (!g_IMXContext.Configure()) ++ return false; ++ ++#ifdef DUMP_STREAM ++ m_dump = fopen("stream.dump", "wb"); ++ if (m_dump != NULL) ++ { ++ fwrite(&hints.software, sizeof(hints.software), 1, m_dump); ++ fwrite(&hints.codec, sizeof(hints.codec), 1, m_dump); ++ fwrite(&hints.profile, sizeof(hints.profile), 1, m_dump); ++ fwrite(&hints.codec_tag, sizeof(hints.codec_tag), 1, m_dump); ++ fwrite(&hints.extrasize, sizeof(hints.extrasize), 1, m_dump); ++ CLog::Log(LOGNOTICE, "Dump: HEADER: %d %d %d %d %d\n", ++ hints.software, hints.codec, hints.profile, ++ hints.codec_tag, hints.extrasize); ++ if (hints.extrasize > 0) ++ fwrite(hints.extradata, 1, hints.extrasize, m_dump); ++ } ++#endif ++ + m_hints = hints; + if (g_advancedSettings.CanLogComponent(LOGVIDEO)) + CLog::Log(LOGDEBUG, "Let's decode with iMX VPU\n"); +@@ -494,17 +585,26 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + return true; + } + +-void CDVDVideoCodecIMX::Dispose(void) ++void CDVDVideoCodecIMX::Dispose() + { ++#ifdef DUMP_STREAM ++ if (m_dump) ++ { ++ fclose(m_dump); ++ m_dump = NULL; ++ } ++#endif ++ ++ g_IMXContext.Clear(); ++ + VpuDecRetCode ret; + bool VPU_loaded = m_vpuHandle; + +- // Prevent rendering thread from using frame buffers +- Enter(); +- + // Release last buffer +- if(m_lastBuffer) +- SAFE_RELEASE(m_lastBuffer); ++ SAFE_RELEASE(m_lastBuffer); ++ SAFE_RELEASE(m_currentBuffer); ++ ++ Enter(); + + // Invalidate output buffers to prevent the renderer from mapping this memory + for (int i=0; iClose(); + SAFE_DELETE(m_converter); + } ++ + return; + } + +@@ -579,9 +680,26 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + + #ifdef IMX_PROFILE + static unsigned long long previous, current; ++#endif ++#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) + unsigned long long before_dec; + #endif + ++#ifdef DUMP_STREAM ++ if (m_dump != NULL) ++ { ++ if (pData) ++ { ++ fwrite(&dts, sizeof(double), 1, m_dump); ++ fwrite(&pts, sizeof(double), 1, m_dump); ++ fwrite(&iSize, sizeof(int), 1, m_dump); ++ fwrite(pData, 1, iSize, m_dump); ++ } ++ } ++#endif ++ ++ SAFE_RELEASE(m_currentBuffer); ++ + if (!m_vpuHandle) + { + VpuOpen(); +@@ -610,6 +728,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + if ((pData && iSize) || + (m_bytesToBeConsumed)) + { ++ //printf("D %f %d\n", pts, iSize); + if ((m_convert_bitstream) && (iSize)) + { + // convert demuxer packet from bitstream to bytestream (AnnexB) +@@ -638,16 +757,24 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + inData.sCodecData.nSize = 0; + } + ++#ifdef IMX_PROFILE_BUFFERS ++ static unsigned long long dec_time = 0; ++#endif ++ + while (true) // Decode as long as the VPU consumes data + { +-#ifdef IMX_PROFILE ++#if defined(IMX_PROFILE) || defined(IMX_PROFILE_BUFFERS) + before_dec = XbmcThreads::SystemClockMillis(); + #endif + if (m_frameReported) + m_bytesToBeConsumed += inData.nSize; + ret = VPU_DecDecodeBuf(m_vpuHandle, &inData, &decRet); ++#ifdef IMX_PROFILE_BUFFERS ++ unsigned long long dec_single_call = XbmcThreads::SystemClockMillis()-before_dec; ++ dec_time += dec_single_call; ++#endif + #ifdef IMX_PROFILE +- CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, XbmcThreads::SystemClockMillis() - before_dec); ++ CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, XbmcThreads::SystemClockMillis() - before_dec); + #endif + + if (ret != VPU_DEC_RET_SUCCESS) +@@ -736,14 +863,53 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + m_frameInfo.pExtInfo->nFrmWidth = (((m_frameInfo.pExtInfo->nFrmWidth) + 15) & ~15); + m_frameInfo.pExtInfo->nFrmHeight = (((m_frameInfo.pExtInfo->nFrmHeight) + 15) & ~15); + +- /* quick & dirty fix to get proper timestamping for VP8 codec */ +- if (m_decOpenParam.CodecFormat == VPU_V_VP8) ++ idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); ++ if (idx != -1) + { +- idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); +- m_outputBuffers[idx]->SetPts(pts); +- } ++ CDVDVideoCodecIMXVPUBuffer *buffer = m_outputBuffers[idx]; ++ ++ /* quick & dirty fix to get proper timestamping for VP8 codec */ ++ if (m_decOpenParam.CodecFormat == VPU_V_VP8) ++ buffer->SetPts(pts); ++ ++ buffer->Lock(); ++ buffer->SetDts(dts); ++ buffer->Queue(&m_frameInfo, m_lastBuffer); ++ ++#ifdef IMX_PROFILE_BUFFERS ++ CLog::Log(LOGNOTICE, "+D %f %lld\n", buffer->GetPts(), dec_time); ++ dec_time = 0; ++#endif ++ ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); ++#endif ++ ++ if (!m_usePTS) ++ { ++ buffer->SetPts(DVD_NOPTS_VALUE); ++ buffer->SetDts(DVD_NOPTS_VALUE); ++ } ++ ++ // Save last buffer ++ SAFE_RELEASE(m_lastBuffer); ++ m_lastBuffer = buffer; ++ m_lastBuffer->Lock(); + +- retStatus |= VC_PICTURE; ++#ifdef IMX_PROFILE_BUFFERS ++ static unsigned long long lastD = 0; ++ unsigned long long current = XbmcThreads::SystemClockMillis(), tmp; ++ CLog::Log(LOGNOTICE, "+V %f %lld\n", buffer->GetPts(), current-lastD); ++ lastD = current; ++#endif ++ ++ m_currentBuffer = buffer; ++ ++ if (m_currentBuffer) ++ { ++ retStatus |= VC_PICTURE; ++ } ++ } + } //VPU_DEC_OUTPUT_DIS + + // According to libfslvpuwrap: If this flag is set then the frame should +@@ -822,10 +988,8 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } // Decode loop + } //(pData && iSize) + +- if (retStatus == 0) +- { ++ if (!retStatus) + retStatus |= VC_BUFFER; +- } + + if (m_bytesToBeConsumed > 0) + { +@@ -835,8 +999,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + // at next call... + m_previousPts = pts; + } +- // Store current dts (will be used only if VC_PICTURE is set) +- m_dts = dts; + + #ifdef IMX_PROFILE + CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, XbmcThreads::SystemClockMillis() - previous); +@@ -855,8 +1017,8 @@ void CDVDVideoCodecIMX::Reset() + CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); + + // Release last buffer +- if(m_lastBuffer) +- SAFE_RELEASE(m_lastBuffer); ++ SAFE_RELEASE(m_lastBuffer); ++ SAFE_RELEASE(m_currentBuffer); + + // Invalidate all buffers + for(int i=0; i < m_vpuFrameBufferNum; i++) +@@ -872,12 +1034,11 @@ void CDVDVideoCodecIMX::Reset() + { + CLog::Log(LOGERROR, "%s - VPU flush failed with error code %d.\n", __FUNCTION__, ret); + } +- + } + + unsigned CDVDVideoCodecIMX::GetAllowedReferences() + { +- return 3; ++ return RENDER_QUEUE_SIZE; + } + + bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) +@@ -909,46 +1070,29 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + else + pDvdVideoPicture->iFlags &= ~DVP_FLAG_DROPPED; + ++ if (m_initInfo.nInterlace) ++ pDvdVideoPicture->iFlags |= DVP_FLAG_INTERLACED; ++ else ++ pDvdVideoPicture->iFlags &= ~DVP_FLAG_INTERLACED; ++ ++ if (m_currentBuffer->GetFieldType() != VPU_FIELD_BOTTOM && m_currentBuffer->GetFieldType() != VPU_FIELD_BT) ++ pDvdVideoPicture->iFlags |= DVP_FLAG_TOP_FIELD_FIRST; ++ else ++ pDvdVideoPicture->iFlags &= ~DVP_FLAG_TOP_FIELD_FIRST; ++ + pDvdVideoPicture->format = RENDER_FMT_IMXMAP; +- pDvdVideoPicture->dts = DVD_NOPTS_VALUE; + pDvdVideoPicture->iWidth = m_frameInfo.pExtInfo->FrmCropRect.nRight - m_frameInfo.pExtInfo->FrmCropRect.nLeft; + pDvdVideoPicture->iHeight = m_frameInfo.pExtInfo->FrmCropRect.nBottom - m_frameInfo.pExtInfo->FrmCropRect.nTop; + + pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; + pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + +- int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); +- if (idx != -1) +- { +- CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; +- +- pDvdVideoPicture->pts = buffer->GetPts(); +- pDvdVideoPicture->dts = m_dts; +- if (!m_usePTS) +- { +- pDvdVideoPicture->pts = DVD_NOPTS_VALUE; +- pDvdVideoPicture->dts = DVD_NOPTS_VALUE; +- } ++ // Current buffer is locked already -> hot potato ++ pDvdVideoPicture->pts = m_currentBuffer->GetPts(); ++ pDvdVideoPicture->dts = m_currentBuffer->GetDts(); + +- buffer->Queue(&m_frameInfo, m_lastBuffer); +- +-#ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); +-#endif +- +- pDvdVideoPicture->IMXBuffer = buffer; +- pDvdVideoPicture->IMXBuffer->Lock(); +- +- // Save last buffer +- if (m_lastBuffer) +- SAFE_RELEASE(m_lastBuffer); +- m_lastBuffer = buffer; +- m_lastBuffer->Lock(); +- } +- else +- { +- CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); +- } ++ pDvdVideoPicture->IMXBuffer = m_currentBuffer; ++ m_currentBuffer = NULL; + + return true; + } +@@ -980,44 +1124,64 @@ void CDVDVideoCodecIMX::Leave() + } + + /*******************************************/ +- + #ifdef TRACE_FRAMES + CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx) +- : m_refs(1) +- , m_idx(idx) ++ : m_idx(idx) ++ , + #else + CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() +- : m_refs(1) ++ : ++#endif ++ m_pts(DVD_NOPTS_VALUE) ++ , m_dts(DVD_NOPTS_VALUE) ++{ ++} ++ ++void CDVDVideoCodecIMXBuffer::SetPts(double pts) ++{ ++ m_pts = pts; ++} ++ ++void CDVDVideoCodecIMXBuffer::SetDts(double dts) ++{ ++ m_dts = dts; ++} ++ ++#ifdef TRACE_FRAMES ++CDVDVideoCodecIMXVPUBuffer::CDVDVideoCodecIMXVPUBuffer(int idx) ++ : CDVDVideoCodecIMXBuffer(idx) ++#else ++CDVDVideoCodecIMXVPUBuffer::CDVDVideoCodecIMXVPUBuffer() ++ : CDVDVideoCodecIMXBuffer() + #endif + , m_frameBuffer(NULL) + , m_rendered(false) +- , m_pts(DVD_NOPTS_VALUE) + , m_previousBuffer(NULL) + { + } + +-void CDVDVideoCodecIMXBuffer::Lock() ++void CDVDVideoCodecIMXVPUBuffer::Lock() + { + #ifdef TRACE_FRAMES +- long count = AtomicIncrement(&m_refs); ++ long count = AtomicIncrement(&m_iRefs); + CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (VPU)\n", m_idx, count); + #else +- AtomicIncrement(&m_refs); ++ AtomicIncrement(&m_iRefs); + #endif + } + +-long CDVDVideoCodecIMXBuffer::Release() ++long CDVDVideoCodecIMXVPUBuffer::Release() + { +- long count = AtomicDecrement(&m_refs); ++ long count = AtomicDecrement(&m_iRefs); + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "R- %02d - ref : %d (VPU)\n", m_idx, count); + #endif + if (count == 2) + { +- // Only referenced by the coded and its next frame, release the previous ++ // Only referenced by the codec and its next frame, release the previous + SAFE_RELEASE(m_previousBuffer); + } +- if (count == 1) ++ else if (count == 1) + { + // If count drops to 1 then the only reference is being held by the codec + // that it can be released in the next Decode call. +@@ -1038,18 +1202,18 @@ long CDVDVideoCodecIMXBuffer::Release() + return count; + } + +-bool CDVDVideoCodecIMXBuffer::IsValid() ++bool CDVDVideoCodecIMXVPUBuffer::IsValid() + { + return m_frameBuffer != NULL; + } + +-bool CDVDVideoCodecIMXBuffer::Rendered() const ++bool CDVDVideoCodecIMXVPUBuffer::Rendered() const + { + return m_rendered; + } + +-void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo, +- CDVDVideoCodecIMXBuffer *previous) ++void CDVDVideoCodecIMXVPUBuffer::Queue(VpuDecOutFrameInfo *frameInfo, ++ CDVDVideoCodecIMXVPUBuffer *previous) + { + // No lock necessary because at this time there is definitely no + // thread still holding a reference +@@ -1059,13 +1223,19 @@ void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo, + if (m_previousBuffer) + m_previousBuffer->Lock(); + +- m_iWidth = frameInfo->pExtInfo->nFrmWidth; +- m_iHeight = frameInfo->pExtInfo->nFrmHeight; +- m_VirtAddr = m_frameBuffer->pbufVirtY; +- m_phyAddr = m_frameBuffer->pbufY; ++#ifdef IMX_INPUT_FORMAT_I420 ++ iFormat = _4CC('I', '4', '2', '0'); ++#else ++ iFormat = _4CC('N', 'V', '1', '2'); ++#endif ++ iWidth = frameInfo->pExtInfo->nFrmWidth; ++ iHeight = frameInfo->pExtInfo->nFrmHeight; ++ pVirtAddr = m_frameBuffer->pbufVirtY; ++ pPhysAddr = (int)m_frameBuffer->pbufY; ++ m_fieldType = frameInfo->eFieldType; + } + +-VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) ++VpuDecRetCode CDVDVideoCodecIMXVPUBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + { + // Again no lock required because this is only issued after the last + // external reference was released +@@ -1082,31 +1252,679 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + #endif + m_rendered = false; + m_frameBuffer = NULL; +- m_pts = DVD_NOPTS_VALUE; ++ SetPts(DVD_NOPTS_VALUE); + SAFE_RELEASE(m_previousBuffer); + + return ret; + } + +-void CDVDVideoCodecIMXBuffer::SetPts(double pts) ++CDVDVideoCodecIMXVPUBuffer::~CDVDVideoCodecIMXVPUBuffer() + { +- m_pts = pts; ++ assert(m_iRefs == 0); ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "~ %02d (VPU)\n", m_idx); ++#endif + } + +-double CDVDVideoCodecIMXBuffer::GetPts(void) const ++CIMXContext::CIMXContext() ++ : CThread("iMX IPU") ++ , m_fbHandle(0) ++ , m_fbPages(0) ++ , m_fbPhysAddr(0) ++ , m_fbVirtAddr(NULL) ++ , m_ipuHandle(0) ++ , m_vsync(true) ++ , m_pageCrops(NULL) + { +- return m_pts; ++ // Limit queue to 2 ++ m_input.resize(2); ++ m_beginInput = m_endInput = m_bufferedInput = 0; + } + +-CDVDVideoCodecIMXBuffer *CDVDVideoCodecIMXBuffer::GetPreviousBuffer() const ++CIMXContext::~CIMXContext() + { +- return m_previousBuffer; ++ Close(); + } + +-CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() ++bool CIMXContext::Configure(int pages) + { +- assert(m_refs == 0); +-#ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "~ %02d (VPU)\n", m_idx); ++ SetBlitRects(CRectInt(), CRectInt()); ++ m_fbCurrentPage = 0; ++ ++ int fb0 = open("/dev/fb0", O_RDWR, 0); ++ ++ if (fb0 < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to open /dev/fb0\n"); ++ return false; ++ } ++ ++ struct fb_var_screeninfo fbVar; ++ if (ioctl(fb0, FBIOGET_VSCREENINFO, &fbVar) < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to read primary screen resolution\n"); ++ close(fb0); ++ return false; ++ } ++ ++ close(fb0); ++ ++ if (m_fbHandle) ++ { ++ // Check for updated screen resolution ++ if ((m_fbWidth != fbVar.xres) || (m_fbHeight != fbVar.yres) || (pages != m_fbPages)) ++ Close(); ++ else ++ { ++ Clear(); ++ Unblank(); ++ return true; ++ } ++ } ++ ++ CLog::Log(LOGNOTICE, "iMX : Initialize render buffers\n"); ++ ++ memcpy(&m_fbVar, &fbVar, sizeof(fbVar)); ++ ++ const char *deviceName = "/dev/fb1"; ++ ++ m_fbHandle = open(deviceName, O_RDWR | O_NONBLOCK, 0); ++ if (m_fbHandle < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to open framebuffer: %s\n", deviceName); ++ return false; ++ } ++ ++ m_fbWidth = m_fbVar.xres; ++ m_fbHeight = m_fbVar.yres; ++ ++ if (ioctl(m_fbHandle, FBIOGET_VSCREENINFO, &m_fbVar) < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to query variable screen info at %s\n", deviceName); ++ return false; ++ } ++ ++ // We want n fb pages ++ m_fbPages = pages; ++ m_pageCrops = new CRectInt[m_fbPages]; ++ ++ m_fbVar.xoffset = 0; ++ m_fbVar.yoffset = 0; ++ m_fbVar.bits_per_pixel = 16; ++ m_fbVar.nonstd = _4CC('U', 'Y', 'V', 'Y'); ++ m_fbVar.activate = FB_ACTIVATE_NOW; ++ m_fbVar.xres = m_fbWidth; ++ m_fbVar.yres = m_fbHeight; ++ // One additional line that is required for deinterlacing ++ m_fbVar.yres_virtual = (m_fbVar.yres+1) * m_fbPages; ++ m_fbVar.xres_virtual = m_fbVar.xres; ++ ++ if (ioctl(m_fbHandle, FBIOPUT_VSCREENINFO, &m_fbVar) < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to setup %s\n", deviceName); ++ close(m_fbHandle); ++ m_fbHandle = 0; ++ m_fbPages = 0; ++ return false; ++ } ++ ++ struct fb_fix_screeninfo fb_fix; ++ if (ioctl(m_fbHandle, FBIOGET_FSCREENINFO, &fb_fix) < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to query fixed screen info at %s\n", deviceName); ++ close(m_fbHandle); ++ m_fbHandle = 0; ++ m_fbPages = 0; ++ return false; ++ } ++ ++ // Final setup ++ m_fbLineLength = fb_fix.line_length; ++ m_fbPhysSize = fb_fix.smem_len; ++ m_fbPageSize = m_fbLineLength * m_fbVar.yres_virtual / m_fbPages; ++ m_fbPhysAddr = fb_fix.smem_start; ++ m_fbVirtAddr = (uint8_t*)mmap(0, m_fbPhysSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_fbHandle, 0); ++ ++ CLog::Log(LOGDEBUG, "iMX : Allocated %d render buffers\n", m_fbPages); ++ ++ m_ipuHandle = open("/dev/mxc_ipu", O_RDWR, 0); ++ if (m_ipuHandle < 0) ++ { ++ CLog::Log(LOGWARNING, "iMX : Failed to initialize IPU: %s\n", strerror(errno)); ++ m_ipuHandle = 0; ++ Close(); ++ return false; ++ } ++ ++ Clear(); ++ Unblank(); ++ ++ // Start the ipu thread ++ Create(); ++ return true; ++} ++ ++bool CIMXContext::Close() ++{ ++ CLog::Log(LOGINFO, "iMX : Closing context\n"); ++ ++ // Stop the ipu thread ++ StopThread(); ++ ++ if (m_pageCrops) ++ { ++ delete[] m_pageCrops; ++ m_pageCrops = NULL; ++ } ++ ++ if (m_fbVirtAddr) ++ { ++ Clear(); ++ munmap(m_fbVirtAddr, m_fbPhysSize); ++ m_fbVirtAddr = NULL; ++ } ++ ++ if (m_fbHandle) ++ { ++ Blank(); ++ close(m_fbHandle); ++ m_fbPages = 0; ++ m_fbHandle = 0; ++ m_fbPhysAddr = 0; ++ } ++ ++ if (m_ipuHandle) ++ { ++ // Close IPU device ++ if (close(m_ipuHandle)) ++ CLog::Log(LOGERROR, "iMX : Failed to close IPU: %s\n", strerror(errno)); ++ ++ m_ipuHandle = 0; ++ } ++ ++ CLog::Log(LOGNOTICE, "iMX : Deinitialized render context\n", m_fbPages); ++ ++ return true; ++} ++ ++bool CIMXContext::GetPageInfo(CIMXBuffer *info, int page) ++{ ++ if (page < 0 || page >= m_fbPages) ++ return false; ++ ++ info->iWidth = m_fbWidth; ++ info->iHeight = m_fbHeight; ++ info->iFormat = m_fbVar.nonstd; ++ info->pPhysAddr = m_fbPhysAddr + page*m_fbPageSize; ++ info->pVirtAddr = m_fbVirtAddr + page*m_fbPageSize; ++ ++ return true; ++} ++ ++bool CIMXContext::Blank() ++{ ++ if (!m_fbHandle) return false; ++ return ioctl(m_fbHandle, FBIOBLANK, 1) == 0; ++} ++ ++bool CIMXContext::Unblank() ++{ ++ if (!m_fbHandle) return false; ++ return ioctl(m_fbHandle, FBIOBLANK, FB_BLANK_UNBLANK) == 0; ++} ++ ++bool CIMXContext::SetVSync(bool enable) ++{ ++ m_vsync = enable; ++} ++ ++void CIMXContext::SetDoubleRate(bool flag) ++{ ++ if (flag) ++ m_currentFieldFmt |= IPU_DEINTERLACE_RATE_EN; ++ else ++ m_currentFieldFmt &= ~IPU_DEINTERLACE_RATE_EN; ++ ++ m_currentFieldFmt &= ~IPU_DEINTERLACE_RATE_FRAME1; ++} ++ ++bool CIMXContext::DoubleRate() const ++{ ++ return m_currentFieldFmt & IPU_DEINTERLACE_RATE_EN; ++} ++ ++void CIMXContext::SetInterpolatedFrame(bool flag) ++{ ++ if (flag) ++ m_currentFieldFmt &= ~IPU_DEINTERLACE_RATE_FRAME1; ++ else ++ m_currentFieldFmt |= IPU_DEINTERLACE_RATE_FRAME1; ++} ++ ++void CIMXContext::SetDeInterlacing(bool flag) ++{ ++ m_deInterlacing = flag; ++} ++ ++void CIMXContext::SetBlitRects(const CRect &srcRect, const CRect &dstRect) ++{ ++ m_srcRect = srcRect; ++ m_dstRect = dstRect; ++} ++ ++bool CIMXContext::Blit(int page, CIMXBuffer *source_p, CIMXBuffer *source, bool topBottomFields) ++{ ++ if (page < 0 || page >= m_fbPages) ++ return false; ++ ++ IPUTask ipu; ++ PrepareTask(ipu, source_p, source, topBottomFields); ++ return DoTask(ipu, page); ++} ++ ++bool CIMXContext::BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source, bool topBottomFields) ++{ ++ IPUTask ipu; ++ PrepareTask(ipu, source_p, source, topBottomFields); ++ return PushTask(ipu); ++} ++ ++bool CIMXContext::ShowPage(int page) ++{ ++ int ret; ++ ++ if (!m_fbHandle) return false; ++ if (page < 0 || page >= m_fbPages) return false; ++ ++ // Protect page swapping from screen capturing that does read the current ++ // front buffer. This is actually not done very frequently so the lock ++ // does not hurt. ++ CSingleLock lk(m_pageSwapLock); ++ ++ m_fbCurrentPage = page; ++ m_fbVar.activate = FB_ACTIVATE_VBL; ++ m_fbVar.yoffset = (m_fbVar.yres+1)*page; ++ if ((ret = ioctl(m_fbHandle, FBIOPAN_DISPLAY, &m_fbVar)) < 0) ++ CLog::Log(LOGWARNING, "Panning failed: %s\n", strerror(errno)); ++ ++ // Wait for sync ++ if (m_vsync) ++ { ++ if (ioctl(m_fbHandle, FBIO_WAITFORVSYNC, 0) < 0) ++ CLog::Log(LOGWARNING, "Vsync failed: %s\n", strerror(errno)); ++ } ++ ++ return true; ++} ++ ++void CIMXContext::Clear(int page) ++{ ++ if (!m_fbVirtAddr) return; ++ ++ uint8_t *tmp_buf; ++ int pixels; ++ ++ if (page < 0) ++ { ++ tmp_buf = m_fbVirtAddr; ++ pixels = m_fbPageSize*m_fbPages/2; ++ } ++ else if (page < m_fbPages) ++ { ++ tmp_buf = m_fbVirtAddr + page*m_fbPageSize; ++ pixels = m_fbPageSize/2; ++ } ++ else ++ // out of range ++ return; ++ ++ for (int i = 0; i < pixels; ++i, tmp_buf += 2) ++ { ++ tmp_buf[0] = 128; ++ tmp_buf[1] = 16; ++ } ++} ++ ++#define clamp_byte(x) (x<0?0:(x>255?255:x)) ++ ++void CIMXContext::CapureDisplay(unsigned char *buffer, int iWidth, int iHeight) ++{ ++ if (m_fbVar.nonstd != _4CC('U', 'Y', 'V', 'Y')) ++ { ++ CLog::Log(LOGWARNING, "iMX : Unknown screen capture format\n"); ++ return; ++ } ++ ++ // Prevent page swaps ++ CSingleLock lk(m_pageSwapLock); ++ if (m_fbCurrentPage < 0 || m_fbCurrentPage >= m_fbPages) ++ { ++ CLog::Log(LOGWARNING, "iMX : Invalid page to capture\n"); ++ return; ++ } ++ ++ int r,g,b,a; ++ int u, y0, v, y1; ++ ++ unsigned char *display = m_fbVirtAddr + m_fbCurrentPage*m_fbPageSize; ++ int iStride = m_fbWidth*2; ++ int oStride = iWidth*4; ++ ++ int cy = 1*(1 << 16); ++ int cr1 = 1.40200*(1 << 16); ++ int cr2 = -0.71414*(1 << 16); ++ int cr3 = 0*(1 << 16); ++ int cb1 = 0*(1 << 16); ++ int cb2 = -0.34414*(1 << 16); ++ int cb3 = 1.77200*(1 << 16); ++ ++ iWidth = std::min(iWidth/2, m_fbWidth/2); ++ iHeight = std::min(iHeight, m_fbHeight); ++ ++ for (int y = 0; y < iHeight; ++y, display += iStride, buffer += oStride) ++ { ++ unsigned char *iLine = display; ++ unsigned char *oLine = buffer; ++ ++ for (int x = 0; x < iWidth; ++x, iLine += 4, oLine += 8 ) ++ { ++ u = iLine[0]-128; ++ y0 = iLine[1]-16; ++ v = iLine[2]-128; ++ y1 = iLine[3]-16; ++ ++ a = 255-oLine[3]; ++ r = (cy*y0 + cb1*u + cr1*v) >> 16; ++ g = (cy*y0 + cb2*u + cr2*v) >> 16; ++ b = (cy*y0 + cb3*u + cr3*v) >> 16; ++ ++ oLine[0] = (clamp_byte(b)*a + oLine[0]*oLine[3])/255; ++ oLine[1] = (clamp_byte(g)*a + oLine[1]*oLine[3])/255; ++ oLine[2] = (clamp_byte(r)*a + oLine[2]*oLine[3])/255; ++ oLine[3] = 255; ++ ++ a = 255-oLine[7]; ++ r = (cy*y0 + cb1*u + cr1*v) >> 16; ++ g = (cy*y0 + cb2*u + cr2*v) >> 16; ++ b = (cy*y0 + cb3*u + cr3*v) >> 16; ++ ++ oLine[4] = (clamp_byte(b)*a + oLine[4]*oLine[7])/255; ++ oLine[5] = (clamp_byte(g)*a + oLine[5]*oLine[7])/255; ++ oLine[6] = (clamp_byte(r)*a + oLine[6]*oLine[7])/255; ++ oLine[7] = 255; ++ } ++ } ++} ++ ++bool CIMXContext::PushTask(const IPUTask &task) ++{ ++ if (!task.current) ++ return false; ++ ++ CSingleLock lk(m_monitor); ++ ++ if (m_bStop) ++ { ++ m_inputNotEmpty.notifyAll(); ++ return false; ++ } ++ ++ // If the input queue is full, wait for a free slot ++ while ((m_bufferedInput == m_input.size()) && !m_bStop) ++ m_inputNotFull.wait(lk); ++ ++ if (m_bStop) ++ { ++ m_inputNotEmpty.notifyAll(); ++ return false; ++ } ++ ++ // Store the value ++ if (task.previous) task.previous->Lock(); ++ task.current->Lock(); ++ ++ memcpy(&m_input[m_endInput], &task, sizeof(IPUTask)); ++ m_endInput = (m_endInput+1) % m_input.size(); ++ ++m_bufferedInput; ++ m_inputNotEmpty.notifyAll(); ++ ++ return true; ++} ++ ++void CIMXContext::PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *source, ++ bool topBottomFields) ++{ ++ // Fill with zeros ++ ipu.Zero(); ++ ipu.previous = source_p; ++ ipu.current = source; ++ ++ CRect srcRect = m_srcRect; ++ CRect dstRect = m_dstRect; ++ CRectInt iSrcRect, iDstRect; ++ ++ float srcWidth = srcRect.Width(); ++ float srcHeight = srcRect.Height(); ++ float dstWidth = dstRect.Width(); ++ float dstHeight = dstRect.Height(); ++ ++ // Project coordinates outside the target buffer rect to ++ // the source rect otherwise the IPU task will fail ++ // This is under the assumption that the srcRect is always ++ // inside the input buffer rect. If that is not the case ++ // it needs to be projected to the ouput buffer rect as well ++ if (dstRect.x1 < 0) ++ { ++ srcRect.x1 -= dstRect.x1*srcWidth / dstWidth; ++ dstRect.x1 = 0; ++ } ++ if (dstRect.x2 > m_fbWidth) ++ { ++ srcRect.x2 -= (dstRect.x2-m_fbWidth)*srcWidth / dstWidth; ++ dstRect.x2 = m_fbWidth; ++ } ++ if (dstRect.y1 < 0) ++ { ++ srcRect.y1 -= dstRect.y1*srcHeight / dstHeight; ++ dstRect.y1 = 0; ++ } ++ if (dstRect.y2 > m_fbHeight) ++ { ++ srcRect.y2 -= (dstRect.y2-m_fbHeight)*srcHeight / dstHeight; ++ dstRect.y2 = m_fbHeight; ++ } ++ ++ iSrcRect.x1 = Align((int)srcRect.x1,8); ++ iSrcRect.y1 = Align((int)srcRect.y1,8); ++ iSrcRect.x2 = Align((int)srcRect.x2,8); ++ iSrcRect.y2 = Align((int)srcRect.y2,8); ++ ++ iDstRect.x1 = Align((int)dstRect.x1,8); ++ iDstRect.y1 = Align((int)dstRect.y1,8); ++ iDstRect.x2 = Align((int)dstRect.x2,8); ++ iDstRect.y2 = Align((int)dstRect.y2,8); ++ ++ ipu.task.input.crop.pos.x = iSrcRect.x1; ++ ipu.task.input.crop.pos.y = iSrcRect.y1; ++ ipu.task.input.crop.w = iSrcRect.Width(); ++ ipu.task.input.crop.h = iSrcRect.Height(); ++ ++ ipu.task.output.crop.pos.x = iDstRect.x1; ++ ipu.task.output.crop.pos.y = iDstRect.y1; ++ ipu.task.output.crop.w = iDstRect.Width(); ++ ipu.task.output.crop.h = iDstRect.Height(); ++ ++ // Setup deinterlacing if enabled ++ if (m_deInterlacing) ++ { ++ ipu.task.input.deinterlace.enable = 1; ++ /* ++ if (source_p) ++ { ++ task.input.deinterlace.motion = MED_MOTION; ++ task.input.paddr = source_p->pPhysAddr; ++ task.input.paddr_n = source->pPhysAddr; ++ } ++ else ++ */ ++ ipu.task.input.deinterlace.motion = HIGH_MOTION; ++ ipu.task.input.deinterlace.field_fmt = m_currentFieldFmt; ++ ++ if (topBottomFields) ++ ipu.task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_TOP; ++ else ++ ipu.task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_BOTTOM; ++ } ++} ++ ++bool CIMXContext::DoTask(IPUTask &ipu, int targetPage) ++{ ++ // Clear page if cropping changes ++ CRectInt dstRect(ipu.task.output.crop.pos.x, ipu.task.output.crop.pos.y, ++ ipu.task.output.crop.pos.x + ipu.task.output.crop.w, ++ ipu.task.output.crop.pos.y + ipu.task.output.crop.h); ++ ++ // Populate input block ++ ipu.task.input.width = ipu.current->iWidth; ++ ipu.task.input.height = ipu.current->iHeight; ++ ipu.task.input.format = ipu.current->iFormat; ++ ipu.task.input.paddr = ipu.current->pPhysAddr; ++ ++ // Populate output block ++ ipu.task.output.width = m_fbWidth; ++ ipu.task.output.height = m_fbHeight; ++ ipu.task.output.format = m_fbVar.nonstd; ++ ipu.task.output.paddr = m_fbPhysAddr + targetPage*m_fbPageSize; ++ ++ if (m_pageCrops[targetPage] != dstRect) ++ { ++ m_pageCrops[targetPage] = dstRect; ++ Clear(targetPage); ++ } ++ ++ if ((ipu.task.input.crop.w <= 0) || (ipu.task.input.crop.h <= 0) ++ || (ipu.task.output.crop.w <= 0) || (ipu.task.output.crop.h <= 0)) ++ return false; ++ ++#ifdef IMX_PROFILE_BUFFERS ++ unsigned long long before = XbmcThreads::SystemClockMillis(); + #endif ++ ++ int ret = IPU_CHECK_ERR_INPUT_CROP; ++ while (ret != IPU_CHECK_OK && ret > IPU_CHECK_ERR_MIN) ++ { ++ ret = ioctl(m_ipuHandle, IPU_CHECK_TASK, &ipu.task); ++ switch (ret) ++ { ++ case IPU_CHECK_OK: ++ break; ++ case IPU_CHECK_ERR_SPLIT_INPUTW_OVER: ++ ipu.task.input.crop.w -= 8; ++ break; ++ case IPU_CHECK_ERR_SPLIT_INPUTH_OVER: ++ ipu.task.input.crop.h -= 8; ++ break; ++ case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER: ++ ipu.task.output.crop.w -= 8; ++ break; ++ case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER: ++ ipu.task.output.crop.h -= 8; ++ break; ++ default: ++ CLog::Log(LOGWARNING, "iMX : unhandled IPU check error: %d\n", ret); ++ return false; ++ } ++ } ++ ++ // Need to find another interface to protect ipu.current from disposing ++ // in CDVDVideoCodecIMX::Dispose. CIMXContext must not have knowledge ++ // about CDVDVideoCodecIMX. ++ CDVDVideoCodecIMX::Enter(); ++ if (ipu.current->IsValid()) ++ ret = ioctl(m_ipuHandle, IPU_QUEUE_TASK, &ipu.task); ++ else ++ ret = 0; ++ CDVDVideoCodecIMX::Leave(); ++ ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno)); ++ return false; ++ } ++ ++ // Duplicate 2nd scandline if double rate is active ++ if (ipu.task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) ++ { ++ uint8_t *pageAddr = m_fbVirtAddr + targetPage*m_fbPageSize; ++ memcpy(pageAddr, pageAddr+m_fbLineLength, m_fbLineLength); ++ } ++ ++#ifdef IMX_PROFILE_BUFFERS ++ unsigned long long after = XbmcThreads::SystemClockMillis(); ++ printf("+P %f %d\n", ((CDVDVideoCodecIMXBuffer*)ipu.current)->GetPts(), (int)(after-before)); ++#endif ++ ++ return true; ++} ++ ++void CIMXContext::OnStartup() ++{ ++ CLog::Log(LOGNOTICE, "iMX : IPU thread started"); ++} ++ ++void CIMXContext::OnExit() ++{ ++ CLog::Log(LOGNOTICE, "iMX : IPU thread terminated"); ++} ++ ++void CIMXContext::StopThread(bool bWait /*= true*/) ++{ ++ CThread::StopThread(false); ++ m_inputNotFull.notifyAll(); ++ m_inputNotEmpty.notifyAll(); ++ if (bWait) ++ CThread::StopThread(true); ++} ++ ++void CIMXContext::Process() ++{ ++ bool ret, useBackBuffer; ++ int backBuffer; ++ ++ while (!m_bStop) ++ { ++ { ++ CSingleLock lk(m_monitor); ++ while (!m_bufferedInput && !m_bStop) ++ m_inputNotEmpty.wait(lk); ++ ++ if (m_bStop) break; ++ ++ useBackBuffer = m_vsync; ++ IPUTask &task = m_input[m_beginInput]; ++ backBuffer = useBackBuffer?1-m_fbCurrentPage:m_fbCurrentPage; ++ ret = DoTask(task, backBuffer); ++ ++ // Free resources ++ task.Done(); ++ ++ m_beginInput = (m_beginInput+1) % m_input.size(); ++ --m_bufferedInput; ++ m_inputNotFull.notifyAll(); ++ } ++ ++ // Show back buffer ++ if (useBackBuffer && ret) ShowPage(backBuffer); ++ } ++ ++ // Mark all pending jobs as done ++ CSingleLock lk(m_monitor); ++ while (m_bufferedInput > 0) ++ { ++ m_input[m_beginInput].Done(); ++ m_beginInput = (m_beginInput+1) % m_input.size(); ++ --m_bufferedInput; ++ } ++ ++ return; + } +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 6533683..50d9efa 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -18,17 +18,198 @@ + * . + * + */ +-#include +-#include +-#include "DVDVideoCodec.h" +-#include "DVDStreamInfo.h" ++ + #include "threads/CriticalSection.h" ++#include "threads/Condition.h" ++#include "threads/Thread.h" + #include "utils/BitstreamConverter.h" ++#include "guilib/Geometry.h" ++#include "DVDVideoCodec.h" ++#include "DVDStreamInfo.h" ++ ++#include ++#include ++#include ++#include ++ ++ ++// The decoding format of the VPU buffer. Comment this to decode ++// as NV12. The VPU works faster with NV12 in combination with ++// deinterlacing. ++// Progressive content seems to be handled faster with I420 whereas ++// interlaced content is processed faster with NV12 as output format. ++//#define IMX_INPUT_FORMAT_I420 + ++// This enables logging of times for Decode, Render->Render, ++// Deinterlace. It helps to profile several stages of ++// processing with respect to changed kernels or other configurations. ++// Since we utilize VPU, IPU and GPU at the same time different kernel ++// priorities to those subsystems can result in a very different user ++// experience. With that setting enabled we can build some statistics, ++// as numbers are always better than "feelings" ++//#define IMX_PROFILE_BUFFERS + + //#define IMX_PROFILE + //#define TRACE_FRAMES + ++// If uncommented a file "stream.dump" will be created in the current ++// directory whenever a new stream is started. This is only for debugging ++// and performance tests. This define must never be active in distributions. ++//#define DUMP_STREAM ++ ++ ++/*>> TO BE MOVED TO A MORE CENTRAL PLACE IN THE SOURCE DIR >>>>>>>>>>>>>>>>>>>*/ ++// Generell description of a buffer used by ++// the IMX context, e.g. for blitting ++class CIMXBuffer { ++public: ++ CIMXBuffer() : m_iRefs(0) {} ++ ++ // Shared pointer interface ++ virtual void Lock() = 0; ++ virtual long Release() = 0; ++ virtual bool IsValid() = 0; ++ ++public: ++ uint32_t iWidth; ++ uint32_t iHeight; ++ int pPhysAddr; ++ uint8_t *pVirtAddr; ++ int iFormat; ++ ++protected: ++ long m_iRefs; ++}; ++ ++ ++// iMX context class that handles all iMX hardware ++// related stuff ++class CIMXContext : private CThread ++{ ++public: ++ CIMXContext(); ++ ~CIMXContext(); ++ ++ bool Configure(int pages = 2); ++ bool Close(); ++ ++ bool Blank(); ++ bool Unblank(); ++ bool SetVSync(bool enable); ++ ++ bool IsValid() const { return m_fbPages > 0; } ++ ++ // Returns the number of available pages ++ int PageCount() const { return m_fbPages; } ++ ++ // Populates a CIMXBuffer with attributes of a page ++ bool GetPageInfo(CIMXBuffer *info, int page); ++ ++ // Blitter configuration ++ void SetDeInterlacing(bool flag); ++ void SetDoubleRate(bool flag); ++ bool DoubleRate() const; ++ void SetInterpolatedFrame(bool flag); ++ ++ void SetBlitRects(const CRect &srcRect, const CRect &dstRect); ++ ++ // Blits a buffer to a particular page. ++ // source_p (previous buffer) is required for de-interlacing ++ // modes LOW_MOTION and MED_MOTION. ++ bool Blit(int targetPage, CIMXBuffer *source_p, ++ CIMXBuffer *source, ++ bool topBottomFields = true); ++ ++ // Same as blit but runs in another thread and returns after the task has ++ // been queued. BlitAsync renders always to the current backbuffer and ++ // swaps the pages. ++ bool BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source, ++ bool topBottomFields = true); ++ ++ // Shows a page vsynced ++ bool ShowPage(int page); ++ ++ // Returns the visible page ++ int GetCurrentPage() const { return m_fbCurrentPage; } ++ ++ // Clears the pages or a single page with 'black' ++ void Clear(int page = -1); ++ ++ // Captures the current visible frame buffer page and blends it into ++ // the passed overlay. The buffer format is BGRA (4 byte) ++ void CapureDisplay(unsigned char *buffer, int iWidth, int iHeight); ++ ++private: ++ struct IPUTask ++ { ++ void Zero() ++ { ++ current = previous = NULL; ++ memset(&task, 0, sizeof(task)); ++ } ++ ++ void Done() ++ { ++ SAFE_RELEASE(previous); ++ SAFE_RELEASE(current); ++ } ++ ++ // Kept for reference ++ CIMXBuffer *previous; ++ CIMXBuffer *current; ++ ++ // The actual task ++ struct ipu_task task; ++ }; ++ ++ bool PushTask(const IPUTask &); ++ void PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *source, ++ bool topBottomFields); ++ bool DoTask(IPUTask &ipu, int targetPage); ++ ++ virtual void OnStartup(); ++ virtual void OnExit(); ++ virtual void StopThread(bool bWait = true); ++ virtual void Process(); ++ ++private: ++ typedef std::vector TaskQueue; ++ ++ int m_fbHandle; ++ int m_fbPages; ++ int m_fbCurrentPage; ++ int m_fbWidth; ++ int m_fbHeight; ++ int m_fbLineLength; ++ int m_fbPageSize; ++ int m_fbPhysSize; ++ int m_fbPhysAddr; ++ uint8_t *m_fbVirtAddr; ++ struct fb_var_screeninfo m_fbVar; ++ int m_ipuHandle; ++ int m_currentFieldFmt; ++ bool m_vsync; ++ bool m_deInterlacing; ++ CRect m_srcRect; ++ CRect m_dstRect; ++ CRectInt m_inputRect; ++ CRectInt m_outputRect; ++ CRectInt *m_pageCrops; ++ ++ CCriticalSection m_pageSwapLock; ++ TaskQueue m_input; ++ volatile int m_beginInput, m_endInput; ++ volatile size_t m_bufferedInput; ++ XbmcThreads::ConditionVariable m_inputNotEmpty; ++ XbmcThreads::ConditionVariable m_inputNotFull; ++ mutable CCriticalSection m_monitor; ++}; ++ ++ ++extern CIMXContext g_IMXContext; ++/*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ ++ ++ + class CDecMemInfo + { + public: +@@ -40,16 +221,17 @@ public: + {} + + //virtual mem info +- int nVirtNum; +- void** virtMem; ++ int nVirtNum; ++ void **virtMem; + + //phy mem info +- int nPhyNum; +- VpuMemDesc* phyMem; ++ int nPhyNum; ++ VpuMemDesc *phyMem; + }; + +-class CDVDVideoCodecIMXBuffer +-{ ++ ++// Base class of IMXVPU and IMXIPU buffer ++class CDVDVideoCodecIMXBuffer : public CIMXBuffer { + public: + #ifdef TRACE_FRAMES + CDVDVideoCodecIMXBuffer(int idx); +@@ -57,95 +239,111 @@ public: + CDVDVideoCodecIMXBuffer(); + #endif + ++ void SetPts(double pts); ++ double GetPts() const { return m_pts; } ++ ++ void SetDts(double dts); ++ double GetDts() const { return m_dts; } ++ ++protected: ++#ifdef TRACE_FRAMES ++ int m_idx; ++#endif ++ ++private: ++ double m_pts; ++ double m_dts; ++}; ++ ++ ++class CDVDVideoCodecIMXVPUBuffer : public CDVDVideoCodecIMXBuffer ++{ ++public: ++#ifdef TRACE_FRAMES ++ CDVDVideoCodecIMXVPUBuffer(int idx); ++#else ++ CDVDVideoCodecIMXVPUBuffer(); ++#endif ++ + // reference counting +- virtual void Lock(); +- virtual long Release(); +- virtual bool IsValid(); +- +- bool Rendered() const; +- void Queue(VpuDecOutFrameInfo *frameInfo, +- CDVDVideoCodecIMXBuffer *previous); +- VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); +- void SetPts(double pts); +- double GetPts(void) const; +- CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const; +- +- uint32_t m_iWidth; +- uint32_t m_iHeight; +- uint8_t *m_phyAddr; +- uint8_t *m_VirtAddr; ++ virtual void Lock(); ++ virtual long Release(); ++ virtual bool IsValid(); ++ ++ bool Rendered() const; ++ void Queue(VpuDecOutFrameInfo *frameInfo, ++ CDVDVideoCodecIMXVPUBuffer *previous); ++ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); ++ CDVDVideoCodecIMXVPUBuffer *GetPreviousBuffer() const { return m_previousBuffer; } ++ VpuFieldType GetFieldType() const { return m_fieldType; } ++ bool IsInterlaced() const { return m_fieldType != VPU_FIELD_NONE; } + + private: + // private because we are reference counted +- virtual ~CDVDVideoCodecIMXBuffer(); ++ virtual ~CDVDVideoCodecIMXVPUBuffer(); + + private: +-#ifdef TRACE_FRAMES +- int m_idx; +-#endif +- long m_refs; +- VpuFrameBuffer *m_frameBuffer; +- bool m_rendered; +- double m_pts; +- CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds a the reference counted +- // previous buffer ++ VpuFieldType m_fieldType; ++ VpuFrameBuffer *m_frameBuffer; ++ bool m_rendered; ++ CDVDVideoCodecIMXVPUBuffer *m_previousBuffer; // Holds a the reference counted ++ // previous buffer + }; + ++ + class CDVDVideoCodecIMX : public CDVDVideoCodec + { +- friend class CDVDVideoCodecIMXBuffer; +- friend class CDVDVideoCodecIPUBuffer; +- + public: + CDVDVideoCodecIMX(); + virtual ~CDVDVideoCodecIMX(); + + // Methods from CDVDVideoCodec which require overrides + virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options); +- virtual void Dispose(void); ++ virtual void Dispose(); + virtual int Decode(BYTE *pData, int iSize, double dts, double pts); +- virtual void Reset(void); ++ virtual void Reset(); + virtual bool ClearPicture(DVDVideoPicture *pDvdVideoPicture); + virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture); + virtual void SetDropState(bool bDrop); +- virtual const char* GetName(void) { return (const char*)m_pFormatName; } ++ virtual const char* GetName() { return (const char*)m_pFormatName; } + virtual unsigned GetAllowedReferences(); + + static void Enter(); + static void Leave(); + + protected: +- + bool VpuOpen(); + bool VpuAllocBuffers(VpuMemInfo *); + bool VpuFreeBuffers(); + bool VpuAllocFrameBuffers(); + int VpuFindBuffer(void *frameAddr); + +- static const int m_extraVpuBuffers; // Number of additional buffers for VPU +- static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop +- static CCriticalSection m_codecBufferLock; // Lock to protect buffers handled +- // by both decoding and rendering threads +- +- CDVDStreamInfo m_hints; // Hints from demuxer at stream opening +- const char *m_pFormatName; // Current decoder format name +- VpuDecOpenParam m_decOpenParam; // Parameters required to call VPU_DecOpen +- CDecMemInfo m_decMemInfo; // VPU dedicated memory description +- VpuDecHandle m_vpuHandle; // Handle for VPU library calls +- VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start +- bool m_dropState; // Current drop state +- int m_vpuFrameBufferNum; // Total number of allocated frame buffers +- VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description +- CDVDVideoCodecIMXBuffer **m_outputBuffers; // Table of VPU output buffers +- CDVDVideoCodecIMXBuffer *m_lastBuffer; // Keep track of previous VPU output buffer (needed by deinterlacing motion engin) +- VpuMemDesc *m_extraMem; // Table of allocated extra Memory +- int m_frameCounter; // Decoded frames counter +- bool m_usePTS; // State whether pts out of decoding process should be used +- VpuDecOutFrameInfo m_frameInfo; // Store last VPU output frame info +- CBitstreamConverter *m_converter; // H264 annex B converter +- bool m_convert_bitstream; // State whether bitstream conversion is required +- int m_bytesToBeConsumed; // Remaining bytes in VPU +- double m_previousPts; // Enable to keep pts when needed +- bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu +- double m_dts; // Current dts ++ static const int m_extraVpuBuffers; // Number of additional buffers for VPU ++ static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop ++ // by both decoding and rendering threads ++ static CCriticalSection m_codecBufferLock; // Lock to protect buffers handled ++ CDVDStreamInfo m_hints; // Hints from demuxer at stream opening ++ const char *m_pFormatName; // Current decoder format name ++ VpuDecOpenParam m_decOpenParam; // Parameters required to call VPU_DecOpen ++ CDecMemInfo m_decMemInfo; // VPU dedicated memory description ++ VpuDecHandle m_vpuHandle; // Handle for VPU library calls ++ VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start ++ bool m_dropState; // Current drop state ++ int m_vpuFrameBufferNum; // Total number of allocated frame buffers ++ VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description ++ CDVDVideoCodecIMXVPUBuffer **m_outputBuffers; // Table of VPU output buffers ++ CDVDVideoCodecIMXVPUBuffer *m_lastBuffer; // Keep track of previous VPU output buffer (needed by deinterlacing motion engin) ++ CDVDVideoCodecIMXVPUBuffer *m_currentBuffer; ++ VpuMemDesc *m_extraMem; // Table of allocated extra Memory ++ int m_frameCounter; // Decoded frames counter ++ bool m_usePTS; // State whether pts out of decoding process should be used ++ VpuDecOutFrameInfo m_frameInfo; // Store last VPU output frame info ++ CBitstreamConverter *m_converter; // H264 annex B converter ++ bool m_convert_bitstream; // State whether bitstream conversion is required ++ int m_bytesToBeConsumed; // Remaining bytes in VPU ++ double m_previousPts; // Enable to keep pts when needed ++ bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu ++#ifdef DUMP_STREAM ++ FILE *m_dump; ++#endif + }; +diff --git a/xbmc/guilib/GUIVideoControl.cpp b/xbmc/guilib/GUIVideoControl.cpp +index 126e95f..2b8c2cf 100644 +--- a/xbmc/guilib/GUIVideoControl.cpp ++++ b/xbmc/guilib/GUIVideoControl.cpp +@@ -77,7 +77,11 @@ void CGUIVideoControl::Render() + region.Intersect(old); + g_graphicsContext.BeginPaint(); + g_graphicsContext.SetScissors(region); ++#ifdef HAS_IMXVPU ++ g_graphicsContext.Clear((16 << 16)|(8 << 8)|16); ++#else + g_graphicsContext.Clear(0); ++#endif + g_graphicsContext.SetScissors(old); + g_graphicsContext.EndPaint(); + } +diff --git a/xbmc/guilib/GUIWindow.h b/xbmc/guilib/GUIWindow.h +index af82934..0e05493 100644 +--- a/xbmc/guilib/GUIWindow.h ++++ b/xbmc/guilib/GUIWindow.h +@@ -101,7 +101,7 @@ public: + /*! \brief Do any post render activities. + Check if window closing animation is finished and finalize window closing. + */ +- void AfterRender(); ++ virtual void AfterRender(); + + /*! \brief Main update function, called every frame prior to rendering + Any window that requires updating on a frame by frame basis (such as to maintain +diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp +index ef97251..fe2080e 100644 +--- a/xbmc/guilib/GUIWindowManager.cpp ++++ b/xbmc/guilib/GUIWindowManager.cpp +@@ -539,7 +539,7 @@ void CGUIWindowManager::RenderPass() const + // we render the dialogs based on their render order. + vector renderList = m_activeDialogs; + stable_sort(renderList.begin(), renderList.end(), RenderOrderSortFunction); +- ++ + for (iDialog it = renderList.begin(); it != renderList.end(); ++it) + { + if ((*it)->IsDialogRunning()) +diff --git a/xbmc/settings/VideoSettings.h b/xbmc/settings/VideoSettings.h +index 6eaef1d..8644250 100644 +--- a/xbmc/settings/VideoSettings.h ++++ b/xbmc/settings/VideoSettings.h +@@ -72,6 +72,9 @@ enum EINTERLACEMETHOD + VS_INTERLACEMETHOD_MMAL_BOB = 27, + VS_INTERLACEMETHOD_MMAL_BOB_HALF = 28, + ++ VS_INTERLACEMETHOD_IMX_FASTMOTION = 29, ++ VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE = 30, ++ + VS_INTERLACEMETHOD_MAX // do not use and keep as last enum value. + }; + +diff --git a/xbmc/utils/Screenshot.cpp b/xbmc/utils/Screenshot.cpp +index db73d4a..35a586e 100644 +--- a/xbmc/utils/Screenshot.cpp ++++ b/xbmc/utils/Screenshot.cpp +@@ -37,6 +37,11 @@ + #include "cores/VideoRenderers/RenderManager.h" + #endif + ++#ifdef HAS_IMXVPU ++// This has to go into another header file ++#include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h" ++#endif ++ + #include "filesystem/File.h" + #include "guilib/GraphicContext.h" + +@@ -156,13 +161,19 @@ bool CScreenshotSurface::capture() + for (int x = 0; x < m_width; x++, swap_pixels+=4) + { + std::swap(swap_pixels[0], swap_pixels[2]); +- } ++ } + #endif + memcpy(m_buffer + y * m_stride, surface + (m_height - y - 1) *m_stride, m_stride); + } + + delete [] surface; + ++#ifdef HAS_IMXVPU ++ // Captures the current visible framebuffer page and blends it into the ++ // captured GL overlay ++ g_IMXContext.CapureDisplay(m_buffer, m_width, m_height); ++#endif ++ + #else + //nothing to take a screenshot from + return false; +diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +index ca65fdc..d350a02 100644 +--- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp ++++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +@@ -266,6 +266,8 @@ void CGUIDialogVideoSettings::InitializeSettings() + entries.push_back(make_pair(16331, VS_INTERLACEMETHOD_MMAL_ADVANCED_HALF)); + entries.push_back(make_pair(16332, VS_INTERLACEMETHOD_MMAL_BOB)); + entries.push_back(make_pair(16333, VS_INTERLACEMETHOD_MMAL_BOB_HALF)); ++ entries.push_back(make_pair(16334, VS_INTERLACEMETHOD_IMX_FASTMOTION)); ++ entries.push_back(make_pair(16335, VS_INTERLACEMETHOD_IMX_FASTMOTION_DOUBLE)); + + /* remove unsupported methods */ + for (StaticIntegerSettingOptions::iterator it = entries.begin(); it != entries.end(); ) +diff --git a/xbmc/video/windows/GUIWindowFullScreen.cpp b/xbmc/video/windows/GUIWindowFullScreen.cpp +index ed7c090..e9beff7 100644 +--- a/xbmc/video/windows/GUIWindowFullScreen.cpp ++++ b/xbmc/video/windows/GUIWindowFullScreen.cpp +@@ -284,7 +284,7 @@ bool CGUIWindowFullScreen::OnAction(const CAction &action) + CStdString strChannel = StringUtils::Format("%i", action.GetID() - REMOTE_0); + if (CGUIDialogNumeric::ShowAndGetNumber(strChannel, g_localizeStrings.Get(19000))) + iChannelNumber = atoi(strChannel.c_str()); +- ++ + if (iChannelNumber > 0) + g_application.OnAction(CAction(ACTION_CHANNEL_SWITCH, (float)iChannelNumber)); + } +@@ -356,7 +356,11 @@ bool CGUIWindowFullScreen::OnAction(const CAction &action) + void CGUIWindowFullScreen::ClearBackground() + { + if (g_renderManager.IsVideoLayer()) ++#ifdef HAS_IMXVPU ++ g_graphicsContext.Clear((16 << 16)|(8 << 8)|16); ++#else + g_graphicsContext.Clear(0); ++#endif + } + + void CGUIWindowFullScreen::OnWindowLoaded() +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 04cadc8..2b8180b 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include "utils/log.h" + #include "utils/RegExp.h" + #include "utils/StringUtils.h" +@@ -54,6 +55,40 @@ void CEGLNativeTypeIMX::Initialize() + { + int fd; + ++ // Check if we can change the framebuffer resolution ++ fd = open("/sys/class/graphics/fb0/mode", O_RDWR); ++ if (fd >= 0) ++ { ++ CLog::Log(LOGNOTICE, "%s - graphics sysfs is writable\n", __FUNCTION__); ++ m_readonly = false; ++ } ++ else ++ { ++ CLog::Log(LOGNOTICE, "%s - graphics sysfs is read-only\n", __FUNCTION__); ++ m_readonly = true; ++ } ++ close(fd); ++ ++ bool alphaBlending = false; ++ std::string bpp; ++ if (SysfsUtils::GetString("/sys/class/graphics/fb0/bits_per_pixel", bpp)) ++ { ++ CLog::Log(LOGWARNING, "%s - determining current bits per pixel failed, assuming 16bpp\n", __FUNCTION__); ++ } ++ else ++ { ++ StringUtils::Trim(bpp); ++ if (bpp == "32") ++ { ++ CLog::Log(LOGNOTICE, "%s - 32bpp: configure alpha blending\n", __FUNCTION__); ++ alphaBlending = true; ++ } ++ else ++ { ++ CLog::Log(LOGNOTICE, "%s - %sbpp: configure color keying\n", __FUNCTION__, bpp.c_str()); ++ } ++ } ++ + fd = open("/dev/fb0",O_RDWR); + if (fd < 0) + { +@@ -61,6 +96,27 @@ void CEGLNativeTypeIMX::Initialize() + return; + } + ++ struct mxcfb_color_key colorKey; ++ struct mxcfb_gbl_alpha gbl_alpha; ++ struct mxcfb_loc_alpha lalpha; ++ memset(&lalpha, 0, sizeof(lalpha)); ++ ++ // Configure local alpha ++ lalpha.enable = alphaBlending?1:0; ++ lalpha.alpha_in_pixel = 1; ++ if (ioctl(fd, MXCFB_SET_LOC_ALPHA, &lalpha) < 0) ++ CLog::Log(LOGERROR, "%s - Failed to setup alpha blending\n", __FUNCTION__); ++ ++ gbl_alpha.alpha = 255; ++ gbl_alpha.enable = alphaBlending?0:1; ++ if (ioctl(fd, MXCFB_SET_GBL_ALPHA, &gbl_alpha) < 0) ++ CLog::Log(LOGERROR, "%s - Failed to setup global alpha\n", __FUNCTION__); ++ ++ colorKey.enable = alphaBlending?0:1; ++ colorKey.color_key = (16 << 16)|(8 << 8)|16; ++ if (ioctl(fd, MXCFB_SET_CLR_KEY, &colorKey) < 0) ++ CLog::Log(LOGERROR, "%s - Failed to setup color keying\n", __FUNCTION__); ++ + // Unblank the fb + if (ioctl(fd, FBIOBLANK, 0) < 0) + { +@@ -69,20 +125,6 @@ void CEGLNativeTypeIMX::Initialize() + + close(fd); + +- // Check if we can change the framebuffer resolution +- fd = open("/sys/class/graphics/fb0/mode", O_RDWR); +- if (fd >= 0) +- { +- CLog::Log(LOGNOTICE, "%s - graphics sysfs is writable", __FUNCTION__); +- m_readonly = false; +- } +- else +- { +- CLog::Log(LOGNOTICE, "%s - graphics sysfs is read-only", __FUNCTION__); +- m_readonly = true; +- } +- close(fd); +- + return; + } + +diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp +index 2bdd4fa..dec2ba9 100644 +--- a/xbmc/windowing/egl/WinSystemEGL.cpp ++++ b/xbmc/windowing/egl/WinSystemEGL.cpp +@@ -31,6 +31,10 @@ + #include "settings/DisplaySettings.h" + #include "guilib/DispResource.h" + #include "threads/SingleLock.h" ++#ifdef HAS_IMXVPU ++// This has to go into another header file ++#include "cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h" ++#endif + #include "utils/log.h" + #include "EGLWrapper.h" + #include "EGLQuirks.h" +@@ -266,7 +270,7 @@ bool CWinSystemEGL::CreateNewWindow(const CStdString& name, bool fullScreen, RES + RESOLUTION_INFO current_resolution; + current_resolution.iWidth = current_resolution.iHeight = 0; + +- m_nWidth = res.iWidth; ++ m_nWidth = res.iWidth; + m_nHeight = res.iHeight; + m_displayWidth = res.iScreenWidth; + m_displayHeight = res.iScreenHeight; +@@ -450,6 +454,9 @@ void CWinSystemEGL::SetVSyncImpl(bool enable) + m_iVSyncMode = 0; + CLog::Log(LOGERROR, "%s,Could not set egl vsync", __FUNCTION__); + } ++#ifdef HAS_IMXVPU ++ g_IMXContext.SetVSync(enable); ++#endif + } + + void CWinSystemEGL::ShowOSMouse(bool show) +-- +1.9.1 + diff --git a/projects/imx6/patches/kodi/kodi-999.96-iMX6-disable-deinterlace-by-default.patch b/projects/imx6/patches/kodi/kodi-999.96-iMX6-disable-deinterlace-by-default.patch deleted file mode 100644 index 806079144f..0000000000 --- a/projects/imx6/patches/kodi/kodi-999.96-iMX6-disable-deinterlace-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 467c583ca00c3512d93745ae6bee7ae26ebcb13e Mon Sep 17 00:00:00 2001 -From: fritsch -Date: Sun, 21 Dec 2014 12:58:30 +0100 -Subject: [PATCH] IMX: Disable deinterlacing by default (user can enable it if - he wants) - ---- - xbmc/settings/VideoSettings.cpp | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/xbmc/settings/VideoSettings.cpp b/xbmc/settings/VideoSettings.cpp -index 65105e8..e61f49a 100644 ---- a/xbmc/settings/VideoSettings.cpp -+++ b/xbmc/settings/VideoSettings.cpp -@@ -29,7 +29,7 @@ - - CVideoSettings::CVideoSettings() - { -- m_DeinterlaceMode = VS_DEINTERLACEMODE_AUTO; -+ m_DeinterlaceMode = VS_DEINTERLACEMODE_OFF; - m_InterlaceMethod = VS_INTERLACEMETHOD_AUTO; - m_ScalingMethod = VS_SCALINGMETHOD_LINEAR; - m_ViewMode = ViewModeNormal; --- -1.9.1 -