From 521df499e133aefc79f3c37c9972cf76ff8d725f Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Tue, 9 Dec 2014 20:58:07 +0100 Subject: [PATCH] kodi: add PR5805 Signed-off-by: Stephan Raue --- .../kodi/patches/kodi-999.92-PR5805-v2.patch | 2742 +++++++++++++++++ 1 file changed, 2742 insertions(+) create mode 100644 packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch diff --git a/packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch b/packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch new file mode 100644 index 0000000000..09bd995e17 --- /dev/null +++ b/packages/mediacenter/kodi/patches/kodi-999.92-PR5805-v2.patch @@ -0,0 +1,2742 @@ +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();