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..64d43df6c8 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-01-renderer-drop-old-tempfix-firstflippage-did-not-work.patch @@ -0,0 +1,99 @@ +From 9ed9dcc8a30bbaf9e23dd8a738ec33824e9f7503 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Fri, 2 Jan 2015 10:02:09 +0100 +Subject: [PATCH 01/16] 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 5425322..69760da 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2227,7 +2227,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.3 + 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..ce619c7b2d --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-02-Set-dirty-flag-in-teletext-dialog-if-required.patch @@ -0,0 +1,95 @@ +From 5c961dd12ad9e7949777e7140636c173924b3523 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Fri, 2 Jan 2015 15:35:33 +0000 +Subject: [PATCH 02/16] 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.3 + 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..7939a0a9cd --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-03-renderer-improve-rendering-to-gui-and-separate-video.patch @@ -0,0 +1,659 @@ +From 33dc66131f501609f2a50db217e0810ef9f876ac Mon Sep 17 00:00:00 2001 +From: smallint +Date: Sat, 16 Aug 2014 17:29:15 +0200 +Subject: [PATCH 03/16] 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 69760da..bc33a79 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2175,9 +2175,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); +@@ -2230,7 +2227,6 @@ void CApplication::Render() + if (!extPlayerActive && g_graphicsContext.IsFullScreenVideo() && !m_pPlayer->IsPausedPlayback()) + { + m_bPresentFrame = g_renderManager.FrameWait(100); +- hasRendered = true; + } + else + { +@@ -2273,8 +2269,6 @@ void CApplication::Render() + if(!g_Windowing.BeginRender()) + return; + +- g_renderManager.FrameMove(); +- + CDirtyRegionList dirtyRegions = g_windowManager.GetDirty(); + if(g_graphicsContext.GetStereoMode()) + { +@@ -2296,8 +2290,6 @@ void CApplication::Render() + hasRendered = true; + } + +- g_renderManager.FrameFinish(); +- + g_Windowing.EndRender(); + + // execute post rendering actions (finalize window closing) +@@ -2322,7 +2314,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.3 + 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..2a871c0ad2 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-04-guilib-mark-control-dirty-when-setting-to-invisible.patch @@ -0,0 +1,25 @@ +From 0eebba44430bb98521d9ff22478a0893869bda03 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Mon, 5 Jan 2015 11:29:15 +0100 +Subject: [PATCH 04/16] 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.3 + 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..14c9422e47 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-05-renderer-exit-gfx-lock-when-waiting-for-present-time.patch @@ -0,0 +1,27 @@ +From 0d91676f4100a43304702c76d737e05cc665cca5 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Tue, 6 Jan 2015 13:13:27 +0100 +Subject: [PATCH 05/16] 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.3 + diff --git a/projects/imx6/patches/kodi/kodi-06-renderer-fix-sequence-from-WaitFrame-Render-FrameMov.patch b/projects/imx6/patches/kodi/kodi-06-renderer-fix-sequence-from-WaitFrame-Render-FrameMov.patch new file mode 100644 index 0000000000..4774eefa90 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-06-renderer-fix-sequence-from-WaitFrame-Render-FrameMov.patch @@ -0,0 +1,94 @@ +From 0607a56a5f0eb916d2c27613bcd8db7d3c357aee Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Fri, 23 Jan 2015 07:41:46 +0100 +Subject: [PATCH 06/16] 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 bc33a79..a79c7dd 100644 +--- a/xbmc/Application.cpp ++++ b/xbmc/Application.cpp +@@ -2217,16 +2217,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 + { +@@ -2327,6 +2328,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 b394d7b..36c2842 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.3 + diff --git a/projects/imx6/patches/kodi/kodi-07-Add-aml_support_hevc-function-and-recognize-S812-chi.patch b/projects/imx6/patches/kodi/kodi-07-Add-aml_support_hevc-function-and-recognize-S812-chi.patch new file mode 100644 index 0000000000..1637df70f0 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-07-Add-aml_support_hevc-function-and-recognize-S812-chi.patch @@ -0,0 +1,80 @@ +From 264be7a32fdb566ecf69933189553128c589c800 Mon Sep 17 00:00:00 2001 +From: Stanislav Vlasic +Date: Mon, 13 Oct 2014 13:20:11 +0200 +Subject: [PATCH 07/16] Add aml_support_hevc function and recognize S812 chip + +--- + xbmc/utils/AMLUtils.cpp | 26 ++++++++++++++++++++++++-- + xbmc/utils/AMLUtils.h | 5 ++++- + 2 files changed, 28 insertions(+), 3 deletions(-) + +diff --git a/xbmc/utils/AMLUtils.cpp b/xbmc/utils/AMLUtils.cpp +index 9553745..ac921db 100644 +--- a/xbmc/utils/AMLUtils.cpp ++++ b/xbmc/utils/AMLUtils.cpp +@@ -159,6 +159,22 @@ void aml_permissions() + } + } + ++bool aml_support_hevc() ++{ ++ char valstr[1024]; ++ if(aml_get_sysfs_str("/sys/class/amstream/vcodec_profile", valstr, 1024) != 0) ++ { ++ return false; ++ } ++ char* p = strstr(valstr, "hevc:"); ++ if(p == NULL) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ + enum AML_DEVICE_TYPE aml_get_device_type() + { + static enum AML_DEVICE_TYPE aml_device_type = AML_DEVICE_TYPE_UNINIT; +@@ -173,8 +189,14 @@ enum AML_DEVICE_TYPE aml_get_device_type() + aml_device_type = AML_DEVICE_TYPE_M3; + else if (cpu_hardware.find("Meson6") != std::string::npos) + aml_device_type = AML_DEVICE_TYPE_M6; +- else if (cpu_hardware.find("Meson8") != std::string::npos) +- aml_device_type = AML_DEVICE_TYPE_M8; ++ else if ((cpu_hardware.find("Meson8") != std::string::npos) && (cpu_hardware.find("Meson8B") == std::string::npos)) ++ { ++ if (aml_support_hevc()) ++ aml_device_type = AML_DEVICE_TYPE_M8M2; ++ else ++ aml_device_type = AML_DEVICE_TYPE_M8; ++ } else if (cpu_hardware.find("Meson8B") != std::string::npos) ++ aml_device_type = AML_DEVICE_TYPE_M8B; + else + aml_device_type = AML_DEVICE_TYPE_UNKNOWN; + } +diff --git a/xbmc/utils/AMLUtils.h b/xbmc/utils/AMLUtils.h +index 9778e9b..208f9d3 100644 +--- a/xbmc/utils/AMLUtils.h ++++ b/xbmc/utils/AMLUtils.h +@@ -28,7 +28,9 @@ enum AML_DEVICE_TYPE + AML_DEVICE_TYPE_M1, + AML_DEVICE_TYPE_M3, + AML_DEVICE_TYPE_M6, +- AML_DEVICE_TYPE_M8 ++ AML_DEVICE_TYPE_M8, // S802 ++ AML_DEVICE_TYPE_M8B, // S805 ++ AML_DEVICE_TYPE_M8M2 // S812 + }; + + enum AML_DISPLAY_AXIS_PARAM +@@ -48,6 +50,7 @@ bool aml_present(); + void aml_permissions(); + bool aml_hw3d_present(); + bool aml_wired_present(); ++bool aml_support_hevc(); + enum AML_DEVICE_TYPE aml_get_device_type(); + void aml_cpufreq_min(bool limit); + void aml_cpufreq_max(bool limit); +-- +1.9.3 + diff --git a/projects/imx6/patches/kodi/kodi-08-CHG-Extract-SysfsUtils-from-the-AML-utils.patch b/projects/imx6/patches/kodi/kodi-08-CHG-Extract-SysfsUtils-from-the-AML-utils.patch new file mode 100644 index 0000000000..ba5f41cf3d --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-08-CHG-Extract-SysfsUtils-from-the-AML-utils.patch @@ -0,0 +1,814 @@ +From 22a9bc18b49eb5858b5c7511c9573a861fa81232 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Wed, 31 Dec 2014 15:08:12 +0100 +Subject: [PATCH 08/16] CHG: Extract SysfsUtils from the AML utils + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp | 46 +++++----- + xbmc/utils/AMLUtils.cpp | 95 ++++---------------- + xbmc/utils/AMLUtils.h | 5 -- + xbmc/utils/Makefile.in | 1 + + xbmc/utils/SysfsUtils.cpp | 104 ++++++++++++++++++++++ + xbmc/utils/SysfsUtils.h | 32 +++++++ + xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp | 100 ++++++++++----------- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 44 ++------- + xbmc/windowing/egl/EGLNativeTypeIMX.h | 2 - + 9 files changed, 234 insertions(+), 195 deletions(-) + create mode 100644 xbmc/utils/SysfsUtils.cpp + create mode 100644 xbmc/utils/SysfsUtils.h + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp +index 26db4a1..b74d361 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp +@@ -33,6 +33,7 @@ + #include "utils/AMLUtils.h" + #include "utils/log.h" + #include "utils/StringUtils.h" ++#include "utils/SysfsUtils.h" + #include "utils/TimeUtils.h" + + #if defined(TARGET_ANDROID) +@@ -1643,7 +1644,7 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) + m_dll->codec_set_cntl_avthresh(&am_private->vcodec, AV_SYNC_THRESH); + m_dll->codec_set_cntl_syncthresh(&am_private->vcodec, 0); + // disable tsync, we are playing video disconnected from audio. +- aml_set_sysfs_int("/sys/class/tsync/enable", 0); ++ SysfsUtils::SetInt("/sys/class/tsync/enable", 0); + + am_private->am_pkt.codec = &am_private->vcodec; + pre_header_feeding(am_private, &am_private->am_pkt); +@@ -1655,15 +1656,15 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) + + m_display_rect = CRect(0, 0, CDisplaySettings::Get().GetCurrentResolutionInfo().iWidth, CDisplaySettings::Get().GetCurrentResolutionInfo().iHeight); + +- char buffer[256] = {0}; +- aml_get_sysfs_str("/sys/class/ppmgr/ppscaler", buffer, 255); +- if (!strstr(buffer, "enabled")) // Scaler not enabled, use screen size ++ std::string strScaler; ++ SysfsUtils::GetString("/sys/class/ppmgr/ppscaler", strScaler); ++ if (strScaler.find("enabled") != std::string::npos) // Scaler not enabled, use screen size + { + CLog::Log(LOGDEBUG, "ppscaler not enabled"); +- memset(buffer, 0, 256); +- aml_get_sysfs_str("/sys/class/display/mode", buffer, 255); ++ std::string mode; ++ SysfsUtils::GetString("/sys/class/display/mode", mode); + RESOLUTION_INFO res; +- if (aml_mode_to_resolution(buffer, &res)) ++ if (aml_mode_to_resolution(mode.c_str(), &res)) + m_display_rect = CRect(0, 0, res.iScreenWidth, res.iScreenHeight); + } + +@@ -1671,11 +1672,11 @@ bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints) + // if display is set to 1080xxx, then disable deinterlacer for HD content + // else bandwidth usage is too heavy and it will slow down video decoder. + char display_mode[256] = {0}; +- aml_get_sysfs_str("/sys/class/display/mode", display_mode, 255); ++ SysfsUtils::GetString("/sys/class/display/mode", display_mode, 255); + if (strstr(display_mode,"1080")) +- aml_set_sysfs_int("/sys/module/di/parameters/bypass_all", 1); ++ SysfsUtils::SetInt("/sys/module/di/parameters/bypass_all", 1); + else +- aml_set_sysfs_int("/sys/module/di/parameters/bypass_all", 0); ++ SysfsUtils::SetInt("/sys/module/di/parameters/bypass_all", 0); + */ + + m_opened = true; +@@ -1708,7 +1709,7 @@ void CAMLCodec::CloseDecoder() + free(am_private->extradata); + am_private->extradata = NULL; + // return tsync to default so external apps work +- aml_set_sysfs_int("/sys/class/tsync/enable", 1); ++ SysfsUtils::SetInt("/sys/class/tsync/enable", 1); + + ShowMainVideo(false); + } +@@ -1721,8 +1722,9 @@ void CAMLCodec::Reset() + return; + + // set the system blackout_policy to leave the last frame showing +- int blackout_policy = aml_get_sysfs_int("/sys/class/video/blackout_policy"); +- aml_set_sysfs_int("/sys/class/video/blackout_policy", 0); ++ int blackout_policy; ++ SysfsUtils::GetInt("/sys/class/video/blackout_policy", blackout_policy); ++ SysfsUtils::SetInt("/sys/class/video/blackout_policy", 0); + + // restore the speed (some amcodec versions require this) + if (m_speed != DVD_PLAYSPEED_NORMAL) +@@ -1742,7 +1744,7 @@ void CAMLCodec::Reset() + pre_header_feeding(am_private, &am_private->am_pkt); + + // restore the saved system blackout_policy value +- aml_set_sysfs_int("/sys/class/video/blackout_policy", blackout_policy); ++ SysfsUtils::SetInt("/sys/class/video/blackout_policy", blackout_policy); + + // reset some interal vars + m_1st_pts = 0; +@@ -2065,7 +2067,7 @@ void CAMLCodec::ShowMainVideo(const bool show) + if (saved_disable_video == disable_video) + return; + +- aml_set_sysfs_int("/sys/class/video/disable_video", disable_video); ++ SysfsUtils::SetInt("/sys/class/video/disable_video", disable_video); + saved_disable_video = disable_video; + } + +@@ -2074,7 +2076,7 @@ void CAMLCodec::SetVideoZoom(const float zoom) + // input zoom range is 0.5 to 2.0 with a default of 1.0. + // output zoom range is 2 to 300 with default of 100. + // we limit that to a range of 50 to 200 with default of 100. +- aml_set_sysfs_int("/sys/class/video/zoom", (int)(100 * zoom)); ++ SysfsUtils::SetInt("/sys/class/video/zoom", (int)(100 * zoom)); + } + + void CAMLCodec::SetVideoContrast(const int contrast) +@@ -2082,19 +2084,19 @@ void CAMLCodec::SetVideoContrast(const int contrast) + // input contrast range is 0 to 100 with default of 50. + // output contrast range is -255 to 255 with default of 0. + int aml_contrast = (255 * (contrast - 50)) / 50; +- aml_set_sysfs_int("/sys/class/video/contrast", aml_contrast); ++ SysfsUtils::SetInt("/sys/class/video/contrast", aml_contrast); + } + void CAMLCodec::SetVideoBrightness(const int brightness) + { + // input brightness range is 0 to 100 with default of 50. + // output brightness range is -127 to 127 with default of 0. + int aml_brightness = (127 * (brightness - 50)) / 50; +- aml_set_sysfs_int("/sys/class/video/brightness", aml_brightness); ++ SysfsUtils::SetInt("/sys/class/video/brightness", aml_brightness); + } + void CAMLCodec::SetVideoSaturation(const int saturation) + { + // output saturation range is -127 to 127 with default of 127. +- aml_set_sysfs_int("/sys/class/video/saturation", saturation); ++ SysfsUtils::SetInt("/sys/class/video/saturation", saturation); + } + + void CAMLCodec::GetRenderFeatures(Features &renderFeatures) +@@ -2110,7 +2112,7 @@ void CAMLCodec::GetRenderFeatures(Features &renderFeatures) + void CAMLCodec::SetVideo3dMode(const int mode3d) + { + CLog::Log(LOGDEBUG, "CAMLCodec::SetVideo3dMode:mode3d(0x%x)", mode3d); +- aml_set_sysfs_int("/sys/class/ppmgr/ppmgr_3d_mode", mode3d); ++ SysfsUtils::SetInt("/sys/class/ppmgr/ppmgr_3d_mode", mode3d); + } + + std::string CAMLCodec::GetStereoMode() +@@ -2313,9 +2315,9 @@ void CAMLCodec::SetVideoRect(const CRect &SrcRect, const CRect &DestRect) + char video_axis[256] = {}; + sprintf(video_axis, "%d %d %d %d", (int)dst_rect.x1, (int)dst_rect.y1, (int)dst_rect.x2, (int)dst_rect.y2); + +- aml_set_sysfs_str("/sys/class/video/axis", video_axis); ++ SysfsUtils::SetString("/sys/class/video/axis", video_axis); + // make sure we are in 'full stretch' so we can stretch +- aml_set_sysfs_int("/sys/class/video/screen_mode", 1); ++ SysfsUtils::SetInt("/sys/class/video/screen_mode", 1); + + // we only get called once gui has changed to something + // that would show video playback, so show it. +diff --git a/xbmc/utils/AMLUtils.cpp b/xbmc/utils/AMLUtils.cpp +index ac921db..c127c84 100644 +--- a/xbmc/utils/AMLUtils.cpp ++++ b/xbmc/utils/AMLUtils.cpp +@@ -28,77 +28,22 @@ + #include "AMLUtils.h" + #include "utils/CPUInfo.h" + #include "utils/log.h" ++#include "utils/SysfsUtils.h" + #include "utils/StringUtils.h" + #include "utils/AMLUtils.h" + #include "guilib/gui3d.h" + +-int aml_set_sysfs_str(const char *path, const char *val) +-{ +- int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644); +- if (fd >= 0) +- { +- write(fd, val, strlen(val)); +- close(fd); +- return 0; +- } +- return -1; +-} +- +-int aml_get_sysfs_str(const char *path, char *valstr, const int size) +-{ +- int fd = open(path, O_RDONLY); +- if (fd >= 0) +- { +- read(fd, valstr, size - 1); +- valstr[strlen(valstr)] = '\0'; +- close(fd); +- return 0; +- } +- +- sprintf(valstr, "%s", "fail"); +- return -1; +-} +- +-int aml_set_sysfs_int(const char *path, const int val) +-{ +- int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644); +- if (fd >= 0) +- { +- char bcmd[16]; +- sprintf(bcmd, "%d", val); +- write(fd, bcmd, strlen(bcmd)); +- close(fd); +- return 0; +- } +- return -1; +-} +- +-int aml_get_sysfs_int(const char *path) +-{ +- int val = -1; +- int fd = open(path, O_RDONLY); +- if (fd >= 0) +- { +- char bcmd[16]; +- read(fd, bcmd, sizeof(bcmd)); +- val = strtol(bcmd, NULL, 16); +- close(fd); +- } +- return val; +-} +- + bool aml_present() + { + static int has_aml = -1; + if (has_aml == -1) + { +- int rtn = aml_get_sysfs_int("/sys/class/audiodsp/digital_raw"); +- if (rtn != -1) ++ if (SysfsUtils::Has("/sys/class/audiodsp/digital_raw")) + has_aml = 1; + else + has_aml = 0; + if (has_aml) +- CLog::Log(LOGNOTICE, "aml_present, rtn(%d)", rtn); ++ CLog::Log(LOGNOTICE, "AML device detected"); + } + return has_aml == 1; + } +@@ -108,10 +53,12 @@ bool aml_hw3d_present() + static int has_hw3d = -1; + if (has_hw3d == -1) + { +- if (aml_get_sysfs_int("/sys/class/ppmgr/ppmgr_3d_mode") != -1) ++ if (SysfsUtils::Has("/sys/class/ppmgr/ppmgr_3d_mode")) + has_hw3d = 1; + else + has_hw3d = 0; ++ if (has_hw3d) ++ CLog::Log(LOGNOTICE, "AML 3D support detected"); + } + return has_hw3d == 1; + } +@@ -121,8 +68,8 @@ bool aml_wired_present() + static int has_wired = -1; + if (has_wired == -1) + { +- char test[64] = {0}; +- if (aml_get_sysfs_str("/sys/class/net/eth0/operstate", test, 63) != -1) ++ std::string test; ++ if (SysfsUtils::GetString("/sys/class/net/eth0/operstate", test) != -1) + has_wired = 1; + else + has_wired = 0; +@@ -161,18 +108,12 @@ void aml_permissions() + + bool aml_support_hevc() + { +- char valstr[1024]; +- if(aml_get_sysfs_str("/sys/class/amstream/vcodec_profile", valstr, 1024) != 0) ++ std::string valstr; ++ if(SysfsUtils::GetString("/sys/class/amstream/vcodec_profile", valstr) != 0) + { + return false; + } +- char* p = strstr(valstr, "hevc:"); +- if(p == NULL) +- { +- return false; +- } +- +- return true; ++ return (valstr.find("hevc:") != std::string::npos); + } + + enum AML_DEVICE_TYPE aml_get_device_type() +@@ -216,7 +157,7 @@ void aml_cpufreq_min(bool limit) + if (limit) + cpufreq = 600000; + +- aml_set_sysfs_int("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", cpufreq); ++ SysfsUtils::SetInt("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", cpufreq); + } + #endif + } +@@ -231,8 +172,8 @@ void aml_cpufreq_max(bool limit) + if (limit) + cpufreq = 800000; + +- aml_set_sysfs_int("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", cpufreq); +- aml_set_sysfs_str("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "ondemand"); ++ SysfsUtils::SetInt("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", cpufreq); ++ SysfsUtils::SetString("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "ondemand"); + } + } + +@@ -244,7 +185,7 @@ void aml_set_audio_passthrough(bool passthrough) + { + // m1 uses 1, m3 and above uses 2 + int raw = aml_get_device_type() == AML_DEVICE_TYPE_M1 ? 1:2; +- aml_set_sysfs_int("/sys/class/audiodsp/digital_raw", passthrough ? raw:0); ++ SysfsUtils::SetInt("/sys/class/audiodsp/digital_raw", passthrough ? raw:0); + } + } + +@@ -314,11 +255,11 @@ void aml_probe_hdmi_audio() + + int aml_axis_value(AML_DISPLAY_AXIS_PARAM param) + { +- char axis[20] = {0}; ++ std::string axis; + int value[8]; + +- aml_get_sysfs_str("/sys/class/display/axis", axis, 19); +- sscanf(axis, "%d %d %d %d %d %d %d %d", &value[0], &value[1], &value[2], &value[3], &value[4], &value[5], &value[6], &value[7]); ++ SysfsUtils::GetString("/sys/class/display/axis", axis); ++ sscanf(axis.c_str(), "%d %d %d %d %d %d %d %d", &value[0], &value[1], &value[2], &value[3], &value[4], &value[5], &value[6], &value[7]); + + return value[param]; + } +diff --git a/xbmc/utils/AMLUtils.h b/xbmc/utils/AMLUtils.h +index 208f9d3..6b0048a 100644 +--- a/xbmc/utils/AMLUtils.h ++++ b/xbmc/utils/AMLUtils.h +@@ -41,11 +41,6 @@ enum AML_DISPLAY_AXIS_PARAM + AML_DISPLAY_AXIS_PARAM_HEIGHT + }; + +-int aml_set_sysfs_str(const char *path, const char *val); +-int aml_get_sysfs_str(const char *path, char *valstr, const int size); +-int aml_set_sysfs_int(const char *path, const int val); +-int aml_get_sysfs_int(const char *path); +- + bool aml_present(); + void aml_permissions(); + bool aml_hw3d_present(); +diff --git a/xbmc/utils/Makefile.in b/xbmc/utils/Makefile.in +index e203447..2d89fcd 100644 +--- a/xbmc/utils/Makefile.in ++++ b/xbmc/utils/Makefile.in +@@ -79,6 +79,7 @@ SRCS += XMLUtils.cpp + SRCS += Utf8Utils.cpp + SRCS += XSLTUtils.cpp + SRCS += ActorProtocol.cpp ++SRCS += SysfsUtils.cpp + + ifeq (@USE_OPENGLES@,1) + SRCS += AMLUtils.cpp +diff --git a/xbmc/utils/SysfsUtils.cpp b/xbmc/utils/SysfsUtils.cpp +new file mode 100644 +index 0000000..ca62986 +--- /dev/null ++++ b/xbmc/utils/SysfsUtils.cpp +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2011-2014 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "SysfsUtils.h" ++#include "utils/log.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++int SysfsUtils::SetString(const std::string& path, const std::string& valstr) ++{ ++ int fd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644); ++ if (fd >= 0) ++ { ++ write(fd, valstr.c_str(), valstr.size()); ++ close(fd); ++ return 0; ++ } ++ CLog::Log(LOGERROR, "%s: error writing %s",__FUNCTION__, path.c_str()); ++ return -1; ++} ++ ++int SysfsUtils::GetString(const std::string& path, std::string& valstr) ++{ ++ int len; ++ char buf[256] = {0}; ++ ++ int fd = open(path.c_str(), O_RDONLY); ++ if (fd >= 0) ++ { ++ valstr.clear(); ++ while ((len = read(fd, buf, 256)) > 0) ++ valstr.append(buf, len); ++ close(fd); ++ return 0; ++ } ++ ++ CLog::Log(LOGERROR, "%s: error reading %s",__FUNCTION__, path.c_str()); ++ valstr = "fail"; ++ return -1; ++} ++ ++int SysfsUtils::SetInt(const std::string& path, const int val) ++{ ++ int fd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0644); ++ if (fd >= 0) ++ { ++ char bcmd[16]; ++ sprintf(bcmd, "%d", val); ++ write(fd, bcmd, strlen(bcmd)); ++ close(fd); ++ return 0; ++ } ++ ++ CLog::Log(LOGERROR, "%s: error writing %s",__FUNCTION__, path.c_str()); ++ return -1; ++} ++ ++int SysfsUtils::GetInt(const std::string& path, int& val) ++{ ++ int fd = open(path.c_str(), O_RDONLY); ++ if (fd >= 0) ++ { ++ char bcmd[16]; ++ read(fd, bcmd, sizeof(bcmd)); ++ val = strtol(bcmd, NULL, 16); ++ close(fd); ++ return 0; ++ } ++ ++ CLog::Log(LOGERROR, "%s: error reading %s",__FUNCTION__, path.c_str()); ++ return -1; ++} ++ ++bool SysfsUtils::Has(const std::string &path) ++{ ++ int fd = open(path.c_str(), O_RDONLY); ++ if (fd >= 0) ++ { ++ close(fd); ++ return true; ++ } ++ return false; ++} +diff --git a/xbmc/utils/SysfsUtils.h b/xbmc/utils/SysfsUtils.h +new file mode 100644 +index 0000000..fe038bf +--- /dev/null ++++ b/xbmc/utils/SysfsUtils.h +@@ -0,0 +1,32 @@ ++#pragma once ++/* ++ * Copyright (C) 2011-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include ++ ++class SysfsUtils ++{ ++public: ++ static int SetString(const std::string& path, const std::string& valstr); ++ static int GetString(const std::string& path, std::string& valstr); ++ static int SetInt(const std::string& path, const int val); ++ static int GetInt(const std::string& path, int& val); ++ static bool Has(const std::string& path); ++}; +diff --git a/xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp b/xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp +index 7064836..0cce3ea 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeAmlogic.cpp +@@ -22,6 +22,7 @@ + #include "guilib/gui3d.h" + #include "utils/AMLUtils.h" + #include "utils/StringUtils.h" ++#include "utils/SysfsUtils.h" + + #include + #include +@@ -49,13 +50,12 @@ CEGLNativeTypeAmlogic::~CEGLNativeTypeAmlogic() + + bool CEGLNativeTypeAmlogic::CheckCompatibility() + { +- char name[256] = {0}; ++ std::string name; + std::string modalias = "/sys/class/graphics/" + m_framebuffer_name + "/device/modalias"; + +- aml_get_sysfs_str(modalias.c_str(), name, 255); +- CStdString strName = name; +- StringUtils::Trim(strName); +- if (strName == "platform:mesonfb") ++ SysfsUtils::GetString(modalias, name); ++ StringUtils::Trim(name); ++ if (name == "platform:mesonfb") + return true; + return false; + } +@@ -127,9 +127,9 @@ bool CEGLNativeTypeAmlogic::DestroyNativeWindow() + + bool CEGLNativeTypeAmlogic::GetNativeResolution(RESOLUTION_INFO *res) const + { +- char mode[256] = {0}; +- aml_get_sysfs_str("/sys/class/display/mode", mode, 255); +- return aml_mode_to_resolution(mode, res); ++ std::string mode; ++ SysfsUtils::GetString("/sys/class/display/mode", mode); ++ return aml_mode_to_resolution(mode.c_str(), res); + } + + bool CEGLNativeTypeAmlogic::SetNativeResolution(const RESOLUTION_INFO &res) +@@ -180,8 +180,8 @@ bool CEGLNativeTypeAmlogic::SetNativeResolution(const RESOLUTION_INFO &res) + + bool CEGLNativeTypeAmlogic::ProbeResolutions(std::vector &resolutions) + { +- char valstr[256] = {0}; +- aml_get_sysfs_str("/sys/class/amhdmitx/amhdmitx0/disp_cap", valstr, 255); ++ std::string valstr; ++ SysfsUtils::GetString("/sys/class/amhdmitx/amhdmitx0/disp_cap", valstr); + std::vector probe_str = StringUtils::Split(valstr, "\n"); + + resolutions.clear(); +@@ -210,7 +210,7 @@ bool CEGLNativeTypeAmlogic::GetPreferredResolution(RESOLUTION_INFO *res) const + bool CEGLNativeTypeAmlogic::ShowWindow(bool show) + { + std::string blank_framebuffer = "/sys/class/graphics/" + m_framebuffer_name + "/blank"; +- aml_set_sysfs_int(blank_framebuffer.c_str(), show ? 0 : 1); ++ SysfsUtils::SetInt(blank_framebuffer.c_str(), show ? 0 : 1); + return true; + } + +@@ -218,7 +218,7 @@ bool CEGLNativeTypeAmlogic::SetDisplayResolution(const char *resolution) + { + CStdString mode = resolution; + // switch display resolution +- aml_set_sysfs_str("/sys/class/display/mode", mode.c_str()); ++ SysfsUtils::SetString("/sys/class/display/mode", mode.c_str()); + SetupVideoScaling(mode.c_str()); + + return true; +@@ -226,67 +226,67 @@ bool CEGLNativeTypeAmlogic::SetDisplayResolution(const char *resolution) + + void CEGLNativeTypeAmlogic::SetupVideoScaling(const char *mode) + { +- aml_set_sysfs_int("/sys/class/graphics/fb0/blank", 1); +- aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0); +- aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0); +- aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 0); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/blank", 1); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/free_scale", 0); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/free_scale", 0); ++ SysfsUtils::SetInt("/sys/class/ppmgr/ppscaler", 0); + + if (strstr(mode, "1080")) + { +- aml_set_sysfs_str("/sys/class/graphics/fb0/request2XScale", "8"); +- aml_set_sysfs_str("/sys/class/graphics/fb1/scale_axis", "1280 720 1920 1080"); +- aml_set_sysfs_str("/sys/class/graphics/fb1/scale", "0x10001"); ++ SysfsUtils::SetString("/sys/class/graphics/fb0/request2XScale", "8"); ++ SysfsUtils::SetString("/sys/class/graphics/fb1/scale_axis", "1280 720 1920 1080"); ++ SysfsUtils::SetString("/sys/class/graphics/fb1/scale", "0x10001"); + } + else + { +- aml_set_sysfs_str("/sys/class/graphics/fb0/request2XScale", "16 1280 720"); ++ SysfsUtils::SetString("/sys/class/graphics/fb0/request2XScale", "16 1280 720"); + } + +- aml_set_sysfs_int("/sys/class/graphics/fb0/blank", 0); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/blank", 0); + } + + void CEGLNativeTypeAmlogic::EnableFreeScale() + { + // enable OSD free scale using frame buffer size of 720p +- aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0); +- aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0); +- aml_set_sysfs_int("/sys/class/graphics/fb0/scale_width", 1280); +- aml_set_sysfs_int("/sys/class/graphics/fb0/scale_height", 720); +- aml_set_sysfs_int("/sys/class/graphics/fb1/scale_width", 1280); +- aml_set_sysfs_int("/sys/class/graphics/fb1/scale_height", 720); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/free_scale", 0); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/free_scale", 0); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/scale_width", 1280); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/scale_height", 720); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/scale_width", 1280); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/scale_height", 720); + + // enable video free scale (scaling to 1920x1080 with frame buffer size 1280x720) +- aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 0); +- aml_set_sysfs_int("/sys/class/video/disable_video", 1); +- aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 1); +- aml_set_sysfs_str("/sys/class/ppmgr/ppscaler_rect", "0 0 1919 1079 0"); +- aml_set_sysfs_str("/sys/class/ppmgr/disp", "1280 720"); ++ SysfsUtils::SetInt("/sys/class/ppmgr/ppscaler", 0); ++ SysfsUtils::SetInt("/sys/class/video/disable_video", 1); ++ SysfsUtils::SetInt("/sys/class/ppmgr/ppscaler", 1); ++ SysfsUtils::SetString("/sys/class/ppmgr/ppscaler_rect", "0 0 1919 1079 0"); ++ SysfsUtils::SetString("/sys/class/ppmgr/disp", "1280 720"); + // +- aml_set_sysfs_int("/sys/class/graphics/fb0/scale_width", 1280); +- aml_set_sysfs_int("/sys/class/graphics/fb0/scale_height", 720); +- aml_set_sysfs_int("/sys/class/graphics/fb1/scale_width", 1280); +- aml_set_sysfs_int("/sys/class/graphics/fb1/scale_height", 720); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/scale_width", 1280); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/scale_height", 720); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/scale_width", 1280); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/scale_height", 720); + // +- aml_set_sysfs_int("/sys/class/video/disable_video", 2); +- aml_set_sysfs_str("/sys/class/display/axis", "0 0 1279 719 0 0 0 0"); +- aml_set_sysfs_str("/sys/class/ppmgr/ppscaler_rect", "0 0 1279 719 1"); ++ SysfsUtils::SetInt("/sys/class/video/disable_video", 2); ++ SysfsUtils::SetString("/sys/class/display/axis", "0 0 1279 719 0 0 0 0"); ++ SysfsUtils::SetString("/sys/class/ppmgr/ppscaler_rect", "0 0 1279 719 1"); + // +- aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 1); +- aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 1); +- aml_set_sysfs_str("/sys/class/graphics/fb0/free_scale_axis", "0 0 1279 719"); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/free_scale", 1); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/free_scale", 1); ++ SysfsUtils::SetString("/sys/class/graphics/fb0/free_scale_axis", "0 0 1279 719"); + } + + void CEGLNativeTypeAmlogic::DisableFreeScale() + { + // turn off frame buffer freescale +- aml_set_sysfs_int("/sys/class/graphics/fb0/free_scale", 0); +- aml_set_sysfs_int("/sys/class/graphics/fb1/free_scale", 0); +- aml_set_sysfs_str("/sys/class/graphics/fb0/free_scale_axis", "0 0 1279 719"); ++ SysfsUtils::SetInt("/sys/class/graphics/fb0/free_scale", 0); ++ SysfsUtils::SetInt("/sys/class/graphics/fb1/free_scale", 0); ++ SysfsUtils::SetString("/sys/class/graphics/fb0/free_scale_axis", "0 0 1279 719"); + +- aml_set_sysfs_int("/sys/class/ppmgr/ppscaler", 0); +- aml_set_sysfs_int("/sys/class/video/disable_video", 0); ++ SysfsUtils::SetInt("/sys/class/ppmgr/ppscaler", 0); ++ SysfsUtils::SetInt("/sys/class/video/disable_video", 0); + // now default video display to off +- aml_set_sysfs_int("/sys/class/video/disable_video", 1); ++ SysfsUtils::SetInt("/sys/class/video/disable_video", 1); + + // revert display axis + int fd0; +@@ -297,9 +297,9 @@ void CEGLNativeTypeAmlogic::DisableFreeScale() + struct fb_var_screeninfo vinfo; + if (ioctl(fd0, FBIOGET_VSCREENINFO, &vinfo) == 0) + { +- char daxis_str[255] = {0}; ++ char daxis_str[256] = {0}; + sprintf(daxis_str, "%d %d %d %d 0 0 0 0", 0, 0, vinfo.xres-1, vinfo.yres-1); +- aml_set_sysfs_str("/sys/class/display/axis", daxis_str); ++ SysfsUtils::SetString("/sys/class/display/axis", daxis_str); + } + close(fd0); + } +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 04cadc8..9893558 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -28,6 +28,7 @@ + #include "utils/log.h" + #include "utils/RegExp.h" + #include "utils/StringUtils.h" ++#include "utils/SysfsUtils.h" + #include "utils/Environment.h" + #include "guilib/gui3d.h" + #include "windowing/WindowingFactory.h" +@@ -190,7 +191,7 @@ bool CEGLNativeTypeIMX::DestroyNativeWindow() + bool CEGLNativeTypeIMX::GetNativeResolution(RESOLUTION_INFO *res) const + { + std::string mode; +- get_sysfs_str("/sys/class/graphics/fb0/mode", mode); ++ SysfsUtils::GetString("/sys/class/graphics/fb0/mode", mode); + return ModeToResolution(mode, res); + } + +@@ -200,14 +201,14 @@ bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res) + return false; + + std::string mode; +- get_sysfs_str("/sys/class/graphics/fb0/mode", mode); ++ SysfsUtils::GetString("/sys/class/graphics/fb0/mode", mode); + if (res.strId == mode) + return false; + + DestroyNativeWindow(); + DestroyNativeDisplay(); + +- set_sysfs_str("/sys/class/graphics/fb0/mode", res.strId); ++ SysfsUtils::SetString("/sys/class/graphics/fb0/mode", res.strId); + + CreateNativeDisplay(); + +@@ -225,7 +226,7 @@ bool CEGLNativeTypeIMX::ProbeResolutions(std::vector &resolutio + return false; + + std::string valstr; +- get_sysfs_str("/sys/class/graphics/fb0/modes", valstr); ++ SysfsUtils::GetString("/sys/class/graphics/fb0/modes", valstr); + std::vector probe_str; + probe_str = StringUtils::Split(valstr, "\n"); + +@@ -257,41 +258,6 @@ bool CEGLNativeTypeIMX::ShowWindow(bool show) + return false; + } + +-int CEGLNativeTypeIMX::get_sysfs_str(std::string path, std::string& valstr) const +-{ +- int len; +- char buf[256] = {0}; +- +- int fd = open(path.c_str(), O_RDONLY); +- if (fd >= 0) +- { +- while ((len = read(fd, buf, 255)) > 0) +- valstr.append(buf, len); +- close(fd); +- } +- else +- { +- CLog::Log(LOGERROR, "%s: error reading %s",__FUNCTION__, path.c_str()); +- valstr = "fail"; +- return -1; +- } +- return 0; +-} +- +-int CEGLNativeTypeIMX::set_sysfs_str(std::string path, std::string val) const +-{ +- int fd = open(path.c_str(), O_WRONLY); +- if (fd >= 0) +- { +- val += '\n'; +- write(fd, val.c_str(), val.size()); +- close(fd); +- return 0; +- } +- CLog::Log(LOGERROR, "%s: error writing %s",__FUNCTION__, path.c_str()); +- return -1; +-} +- + bool CEGLNativeTypeIMX::ModeToResolution(std::string mode, RESOLUTION_INFO *res) const + { + if (!res) +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.h b/xbmc/windowing/egl/EGLNativeTypeIMX.h +index d5e5739..0298cb5 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.h ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.h +@@ -50,8 +50,6 @@ public: + + protected: + bool m_readonly; +- int get_sysfs_str(std::string path, std::string& valstr) const; +- int set_sysfs_str(std::string path, std::string val) const; + bool ModeToResolution(std::string mode, RESOLUTION_INFO *res) const; + + EGLNativeDisplayType m_display; +-- +1.9.3 + diff --git a/projects/imx6/patches/kodi/kodi-09-imx-Fixed-mode-change-after-SysfsUtils-port.patch b/projects/imx6/patches/kodi/kodi-09-imx-Fixed-mode-change-after-SysfsUtils-port.patch new file mode 100644 index 0000000000..98894197c8 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-09-imx-Fixed-mode-change-after-SysfsUtils-port.patch @@ -0,0 +1,25 @@ +From 11a9bc199b0ebd9e6cfb9b82547bb3c5379b1104 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Mon, 19 Jan 2015 20:38:42 +0100 +Subject: [PATCH 09/16] [imx] Fixed mode change after SysfsUtils port + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 9893558..061f6e6 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -208,7 +208,7 @@ bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res) + DestroyNativeWindow(); + DestroyNativeDisplay(); + +- SysfsUtils::SetString("/sys/class/graphics/fb0/mode", res.strId); ++ SysfsUtils::SetString("/sys/class/graphics/fb0/mode", res.strId + "\n"); + + CreateNativeDisplay(); + +-- +1.9.3 + diff --git a/projects/imx6/patches/kodi/kodi-10-imx-Added-de-interlacing-method-enumerations-FAST_MO.patch b/projects/imx6/patches/kodi/kodi-10-imx-Added-de-interlacing-method-enumerations-FAST_MO.patch new file mode 100644 index 0000000000..12274ae0dd --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-10-imx-Added-de-interlacing-method-enumerations-FAST_MO.patch @@ -0,0 +1,67 @@ +From 9c9935180aa9297d35855db674b7eb7f732714e9 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Thu, 5 Feb 2015 19:35:05 +0000 +Subject: [PATCH 10/16] [imx] Added de-interlacing method enumerations + FAST_MOTION and FAST_MOTION_DOUBLE + +--- + language/English/strings.po | 14 +++++++++++++- + xbmc/settings/VideoSettings.h | 3 +++ + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 ++ + 3 files changed, 18 insertions(+), 1 deletion(-) + +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/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/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(); ) +-- +1.9.3 + diff --git a/projects/imx6/patches/kodi/kodi-11-RenderManager-preserve-field-type-for-Renderer-Rende.patch b/projects/imx6/patches/kodi/kodi-11-RenderManager-preserve-field-type-for-Renderer-Rende.patch new file mode 100644 index 0000000000..17793cd645 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-11-RenderManager-preserve-field-type-for-Renderer-Rende.patch @@ -0,0 +1,52 @@ +From ba9b668fcbfd4f6bcfd67b22bcdc850a140ac65c Mon Sep 17 00:00:00 2001 +From: smallint +Date: Thu, 5 Feb 2015 19:37:13 +0000 +Subject: [PATCH 11/16] [RenderManager] preserve field type for + Renderer::RenderUpdate + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 36c2842..85c3565 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -676,7 +676,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) +@@ -691,6 +694,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 */ +@@ -837,8 +841,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, * +-- +1.9.3 + diff --git a/projects/imx6/patches/kodi/kodi-12-imx-Reworked-video-decoding-and-rendering-see-http-f.patch b/projects/imx6/patches/kodi/kodi-12-imx-Reworked-video-decoding-and-rendering-see-http-f.patch new file mode 100644 index 0000000000..fd5ed38378 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-12-imx-Reworked-video-decoding-and-rendering-see-http-f.patch @@ -0,0 +1,2351 @@ +From f868235f00f10e58d682a7786544b495d5113405 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Thu, 5 Feb 2015 19:39:33 +0000 +Subject: [PATCH 12/16] [imx] Reworked video decoding and rendering, see + http://forum.kodi.tv/showthread.php?tid=211289&pid=1892440#pid1892440 + +Conflicts: + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 219 ++-- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 3 + + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1084 +++++++++++++++++--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 319 ++++-- + xbmc/guilib/GUIVideoControl.cpp | 4 + + xbmc/utils/Screenshot.cpp | 13 +- + xbmc/video/windows/GUIWindowFullScreen.cpp | 4 + + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 70 +- + xbmc/windowing/egl/WinSystemEGL.cpp | 9 +- + 9 files changed, 1370 insertions(+), 355 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index a765461..94fb19b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -88,12 +88,6 @@ static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR; + #ifdef HAS_IMXVPU + #include "windowing/egl/EGLWrapper.h" + #include "DVDCodecs/Video/DVDVideoCodecIMX.h" +- +-#define GL_VIV_NV12 0x8FC1 +-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; +-static PFNGLTEXDIRECTINVALIDATEVIVPROC glTexDirectInvalidateVIV; + #endif + + #if defined(TARGET_ANDROID) +@@ -185,13 +179,6 @@ CLinuxRendererGLES::CLinuxRendererGLES() + eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR"); + } + #endif +- +-#ifdef HAS_IMXVPU +- if (!glTexDirectVIVMap) +- glTexDirectVIVMap = (PFNGLTEXDIRECTVIVMAPPROC) CEGLWrapper::GetProcAddress("glTexDirectVIVMap"); +- if (!glTexDirectInvalidateVIV) +- glTexDirectInvalidateVIV = (PFNGLTEXDIRECTINVALIDATEVIVPROC) CEGLWrapper::GetProcAddress("glTexDirectInvalidateVIV"); +-#endif + } + + CLinuxRendererGLES::~CLinuxRendererGLES() +@@ -608,6 +595,64 @@ void CLinuxRendererGLES::RenderUpdateVideo(bool clear, DWORD flags, DWORD alpha) + + return; + } ++#ifdef HAS_IMXVPU ++ else if (m_renderMethod & RENDER_IMXMAP) ++ { ++#if 0 ++ static unsigned long long previous = 0; ++ unsigned long long current = XbmcThreads::SystemClockMillis(); ++ printf("r->r: %d\n", (int)(current-previous)); ++ previous = current; ++#endif ++ CDVDVideoCodecIMXBuffer *buffer = m_buffers[m_iYV12RenderBuffer].IMXBuffer; ++ if (buffer != NULL && buffer->IsValid()) ++ { ++ ManageDisplay(); ++ g_IMXContext.SetBlitRects(m_sourceRect, m_destRect); ++ ++ bool topFieldFirst = true; ++ ++ // Deinterlacing requested ++ if (flags & RENDER_FLAG_FIELDMASK) ++ { ++ if ((buffer->GetFieldType() == VPU_FIELD_BOTTOM) ++ || (buffer->GetFieldType() == VPU_FIELD_BT) ) ++ topFieldFirst = false; ++ ++ if (flags & RENDER_FLAG_FIELD0) ++ { ++ // Double rate first frame ++ g_IMXContext.SetDeInterlacing(true); ++ g_IMXContext.SetDoubleRate(true); ++ g_IMXContext.SetInterpolatedFrame(true); ++ } ++ else if (flags & RENDER_FLAG_FIELD1) ++ { ++ // Double rate second frame ++ g_IMXContext.SetDeInterlacing(true); ++ g_IMXContext.SetDoubleRate(true); ++ g_IMXContext.SetInterpolatedFrame(false); ++ } ++ else ++ { ++ // Fast motion ++ g_IMXContext.SetDeInterlacing(true); ++ g_IMXContext.SetDoubleRate(false); ++ } ++ } ++ // Progressive ++ else ++ g_IMXContext.SetDeInterlacing(false); ++ ++ g_IMXContext.BlitAsync(NULL, buffer, topFieldFirst); ++ } ++ ++#if 0 ++ unsigned long long current2 = XbmcThreads::SystemClockMillis(); ++ printf("r: %d %d\n", m_iYV12RenderBuffer, (int)(current2-current)); ++#endif ++ } ++#endif + } + + void CLinuxRendererGLES::FlipPage(int source) +@@ -963,13 +1008,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 +1280,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,81 +1718,6 @@ void CLinuxRendererGLES::RenderCoreVideoRef(int index, int field) + + void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) + { +-#if defined(HAS_IMXVPU) +-#ifdef DEBUG_VERBOSE +- unsigned int time = XbmcThreads::SystemClockMillis(); +-#endif +- +- YUVPLANE &plane = m_buffers[index].fields[field][0]; +- CDVDVideoCodecIMXBuffer *buffer = m_buffers[index].IMXBuffer; +- +- if(buffer == NULL) return; +- +- CDVDVideoCodecIMX::Enter(); +- +- if(!buffer->IsValid()) +- { +- CDVDVideoCodecIMX::Leave(); +- return; +- } +- +- glDisable(GL_DEPTH_TEST); +- +- glActiveTexture(GL_TEXTURE0); +- glBindTexture(m_textureTarget, plane.id); +- +- g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA); +- +- GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip +- GLfloat ver[4][4]; +- GLfloat tex[4][2]; +- GLfloat col[3] = {1.0f, 1.0f, 1.0f}; +- +- GLint posLoc = g_Windowing.GUIShaderGetPos(); +- GLint texLoc = g_Windowing.GUIShaderGetCoord0(); +- GLint colLoc = g_Windowing.GUIShaderGetCol(); +- +- glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver); +- glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex); +- glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col); +- +- glEnableVertexAttribArray(posLoc); +- glEnableVertexAttribArray(texLoc); +- glEnableVertexAttribArray(colLoc); +- +- // Set vertex coordinates +- for(int i = 0; i < 4; i++) +- { +- ver[i][0] = m_rotatedDestCoords[i].x; +- ver[i][1] = m_rotatedDestCoords[i].y; +- ver[i][2] = 0.0f;// set z to 0 +- ver[i][3] = 1.0f; +- } +- +- // Set texture coordinates +- tex[0][0] = tex[3][0] = plane.rect.x1; +- tex[0][1] = tex[1][1] = plane.rect.y1; +- tex[1][0] = tex[2][0] = plane.rect.x2; +- tex[2][1] = tex[3][1] = plane.rect.y2; +- +- glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx); +- +- glDisableVertexAttribArray(posLoc); +- glDisableVertexAttribArray(texLoc); +- glDisableVertexAttribArray(colLoc); +- +- g_Windowing.DisableGUIShader(); +- VerifyGLState(); +- +- glBindTexture(m_textureTarget, 0); +- VerifyGLState(); +- +- CDVDVideoCodecIMX::Leave(); +- +-#ifdef DEBUG_VERBOSE +- CLog::Log(LOGDEBUG, "RenderIMXMAPTexture %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time); +-#endif +-#endif + } + + bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture) +@@ -2717,42 +2681,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 +2796,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 +2824,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 +2857,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 +2888,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 +2904,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 +2998,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/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index ca0abcc..65adced 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]; + + 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); + #else +- m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(); ++ m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer; + #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); +- } ++ CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; + +- retStatus |= VC_PICTURE; ++ /* 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(); ++ ++#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,54 @@ 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) + , m_frameBuffer(NULL) + , m_rendered(false) +- , m_pts(DVD_NOPTS_VALUE) + , m_previousBuffer(NULL) + { + } + ++void CDVDVideoCodecIMXBuffer::SetPts(double pts) ++{ ++ m_pts = pts; ++} ++ ++void CDVDVideoCodecIMXBuffer::SetDts(double dts) ++{ ++ m_dts = dts; ++} ++ + void CDVDVideoCodecIMXBuffer::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 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. +@@ -1043,6 +1197,16 @@ bool CDVDVideoCodecIMXBuffer::IsValid() + return m_frameBuffer != NULL; + } + ++void CDVDVideoCodecIMXBuffer::BeginRender() ++{ ++ CDVDVideoCodecIMX::Enter(); ++} ++ ++void CDVDVideoCodecIMXBuffer::EndRender() ++{ ++ CDVDVideoCodecIMX::Leave(); ++} ++ + bool CDVDVideoCodecIMXBuffer::Rendered() const + { + return m_rendered; +@@ -1059,10 +1223,16 @@ 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) +@@ -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) ++CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() + { +- 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::CaptureDisplay(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. ++ ipu.current->BeginRender(); ++ if (ipu.current->IsValid()) ++ ret = ioctl(m_ipuHandle, IPU_QUEUE_TASK, &ipu.task); ++ else ++ ret = 0; ++ ipu.current->EndRender(); ++ ++ 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(); ++ CLog::Log(LOGNOTICE, "+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..dca3f2f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -18,17 +18,201 @@ + * . + * + */ +-#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; ++ ++ virtual void BeginRender() = 0; ++ virtual void EndRender() = 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 CaptureDisplay(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 +224,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); +@@ -58,94 +243,98 @@ public: + #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(); ++ ++ virtual void BeginRender(); ++ virtual void EndRender(); ++ ++ void SetPts(double pts); ++ double GetPts() const { return m_pts; } ++ ++ void SetDts(double dts); ++ double GetDts() const { return m_dts; } ++ ++ bool Rendered() const; ++ void Queue(VpuDecOutFrameInfo *frameInfo, ++ CDVDVideoCodecIMXBuffer *previous); ++ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); ++ CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const { return m_previousBuffer; } ++ VpuFieldType GetFieldType() const { return m_fieldType; } + + private: + // private because we are reference counted +- virtual ~CDVDVideoCodecIMXBuffer(); ++ virtual ~CDVDVideoCodecIMXBuffer(); + +-private: ++protected: + #ifdef TRACE_FRAMES + int m_idx; + #endif +- long m_refs; ++ ++private: ++ double m_pts; ++ double m_dts; ++ VpuFieldType m_fieldType; + VpuFrameBuffer *m_frameBuffer; + bool m_rendered; +- double m_pts; +- CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds a the reference counted +- // previous buffer ++ CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds 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 ++ CDVDVideoCodecIMXBuffer **m_outputBuffers; // Table of VPU output buffers ++ CDVDVideoCodecIMXBuffer *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 ++ 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/utils/Screenshot.cpp b/xbmc/utils/Screenshot.cpp +index db73d4a..2335178 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.CaptureDisplay(m_buffer, m_width, m_height); ++#endif ++ + #else + //nothing to take a screenshot from + return false; +diff --git a/xbmc/video/windows/GUIWindowFullScreen.cpp b/xbmc/video/windows/GUIWindowFullScreen.cpp +index ed7c090..17857dd 100644 +--- a/xbmc/video/windows/GUIWindowFullScreen.cpp ++++ b/xbmc/video/windows/GUIWindowFullScreen.cpp +@@ -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 061f6e6..cf2f706 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" +@@ -55,6 +56,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) + { +@@ -62,6 +97,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) + { +@@ -70,20 +126,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.3 + diff --git a/projects/imx6/patches/kodi/kodi-13-implemented-rendercapture-for-latest-rendering-rework.patch b/projects/imx6/patches/kodi/kodi-13-iMX6-Implement-rendercapture-for-latest-rendering-re.patch similarity index 99% rename from projects/imx6/patches/kodi/kodi-13-implemented-rendercapture-for-latest-rendering-rework.patch rename to projects/imx6/patches/kodi/kodi-13-iMX6-Implement-rendercapture-for-latest-rendering-re.patch index e9ae8b5ccf..68e2d3ab4b 100644 --- a/projects/imx6/patches/kodi/kodi-13-implemented-rendercapture-for-latest-rendering-rework.patch +++ b/projects/imx6/patches/kodi/kodi-13-iMX6-Implement-rendercapture-for-latest-rendering-re.patch @@ -1,8 +1,8 @@ -From 03fe0bd48acc0399ede41e220d757ceba8be2937 Mon Sep 17 00:00:00 2001 +From 85ca69f3fc1f9bfd30f828921db1283366c7bfea Mon Sep 17 00:00:00 2001 From: wolfgar Date: Sat, 14 Feb 2015 03:06:03 +0100 -Subject: [PATCH] [iMX6] Implement rendercapture for latest rendering rework - blit fb using g2d when no deinterlacing is required +Subject: [PATCH 13/16] [iMX6] Implement rendercapture for latest rendering + rework blit fb using g2d when no deinterlacing is required --- configure.in | 2 +- @@ -14,7 +14,7 @@ Subject: [PATCH] [iMX6] Implement rendercapture for latest rendering rework 6 files changed, 401 insertions(+), 137 deletions(-) diff --git a/configure.in b/configure.in -index 23bf0aa..d395add 100644 +index 32e37c5..a8cdca0 100644 --- a/configure.in +++ b/configure.in @@ -1935,7 +1935,7 @@ for codecs in `echo $add_codecs | sed 's/,/ /g'`; do @@ -891,5 +891,5 @@ index dca3f2f..e414454 100644 -- -1.9.1 +1.9.3 diff --git a/projects/imx6/patches/kodi/kodi-15-imx-Output-associated-pts-for-TRACE_FRAMES.patch b/projects/imx6/patches/kodi/kodi-15-imx-Output-associated-pts-for-TRACE_FRAMES.patch new file mode 100644 index 0000000000..7f663c51c1 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-15-imx-Output-associated-pts-for-TRACE_FRAMES.patch @@ -0,0 +1,24 @@ +From 1ec717d9197fb0086c76197519f2b522b4ec73af Mon Sep 17 00:00:00 2001 +From: smallint +Date: Fri, 20 Feb 2015 15:40:29 +0100 +Subject: [PATCH 15/16] [imx] Output associated pts for TRACE_FRAMES + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index fcd8b02..7789e38 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -885,6 +885,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, dts, pts); ++ CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, buffer->GetDts(), buffer->GetPts()); + #endif + + if (!m_usePTS) +-- +1.9.3 + diff --git a/projects/imx6/patches/kodi/kodi-16-Add-guard-to-fix-build-on-non-iMX6-arch.patch b/projects/imx6/patches/kodi/kodi-16-Add-guard-to-fix-build-on-non-iMX6-arch.patch new file mode 100644 index 0000000000..6bf9b479b7 --- /dev/null +++ b/projects/imx6/patches/kodi/kodi-16-Add-guard-to-fix-build-on-non-iMX6-arch.patch @@ -0,0 +1,34 @@ +From d2113f254cabde119734440620d16aca7444acd8 Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Sat, 21 Feb 2015 23:45:26 +0100 +Subject: [PATCH 16/16] Add guard to fix build on non iMX6 arch + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 25dbc9b..f482075 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -96,7 +96,7 @@ void CEGLNativeTypeIMX::Initialize() + CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); + return; + } +- ++#ifdef HAS_IMXVPU + struct mxcfb_color_key colorKey; + struct mxcfb_gbl_alpha gbl_alpha; + struct mxcfb_loc_alpha lalpha; +@@ -117,7 +117,7 @@ void CEGLNativeTypeIMX::Initialize() + 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__); +- ++#endif + // Unblank the fb + if (ioctl(fd, FBIOBLANK, 0) < 0) + { +-- +1.9.3 + 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 -