kodi: IMX - implement render capture (wolfgar)

This commit is contained in:
fritsch 2015-02-20 08:14:31 +01:00 committed by Stephan Raue
parent 15da75ea4d
commit ff7d05c3ec

View File

@ -0,0 +1,895 @@
From 03fe0bd48acc0399ede41e220d757ceba8be2937 Mon Sep 17 00:00:00 2001
From: wolfgar <stephan.rafin@laposte.net>
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
---
configure.in | 2 +-
xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 12 +
xbmc/cores/VideoRenderers/RenderCapture.cpp | 43 ++-
xbmc/cores/VideoRenderers/RenderCapture.h | 28 +-
.../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 430 +++++++++++++++------
.../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 23 +-
6 files changed, 401 insertions(+), 137 deletions(-)
diff --git a/configure.in b/configure.in
index 23bf0aa..d395add 100644
--- a/configure.in
+++ b/configure.in
@@ -1935,7 +1935,7 @@ for codecs in `echo $add_codecs | sed 's/,/ /g'`; do
;;
*imxvpu*)
AC_CHECK_HEADER([imx-mm/vpu/vpu_wrapper.h],, AC_MSG_ERROR($missing_headers))
- AC_CHECK_LIB([vpu], main, LIBS="$LIBS -lfslvpuwrap -lvpu", AC_MSG_ERROR($missing_library))
+ AC_CHECK_LIB([vpu], main, LIBS="$LIBS -lfslvpuwrap -lvpu -lg2d", AC_MSG_ERROR($missing_library))
XB_ADD_CODEC([IMXVPU], [imxvpu], [$codecs])
CXXFLAGS="$CXXFLAGS -Wno-psabi -DLINUX "
CFLAGS="$CFLAGS -DLINUX"
diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
index 94fb19b..d523db4 100644
--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
@@ -1733,6 +1733,18 @@ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
return true;
}
+#ifdef HAS_IMXVPU
+ if (m_renderMethod & RENDER_IMXMAP)
+ {
+ CRect rect(0, 0, capture->GetWidth(), capture->GetHeight());
+ CDVDVideoCodecIMXBuffer *buffer = m_buffers[m_iYV12RenderBuffer].IMXBuffer;
+ capture->BeginRender();
+ g_IMXContext.PushCaptureTask(buffer, &rect);
+ capture->EndRender();
+ return true;
+ }
+#endif
+
// save current video rect
CRect saveSize = m_destRect;
saveRotatedCoords();//backup current m_rotatedDestCoords
diff --git a/xbmc/cores/VideoRenderers/RenderCapture.cpp b/xbmc/cores/VideoRenderers/RenderCapture.cpp
index 0fac398..62605c8 100644
--- a/xbmc/cores/VideoRenderers/RenderCapture.cpp
+++ b/xbmc/cores/VideoRenderers/RenderCapture.cpp
@@ -54,7 +54,48 @@ bool CRenderCaptureBase::UseOcclusionQuery()
return true;
}
-#if defined(TARGET_RASPBERRY_PI)
+
+#if defined(HAS_IMXVPU)
+CRenderCaptureIMX::CRenderCaptureIMX()
+{
+}
+
+CRenderCaptureIMX::~CRenderCaptureIMX()
+{
+}
+
+int CRenderCaptureIMX::GetCaptureFormat()
+{
+ return CAPTUREFORMAT_RGBA;
+}
+
+void CRenderCaptureIMX::BeginRender()
+{
+ m_asyncChecked = true;
+ m_asyncSupported = true;
+}
+
+void CRenderCaptureIMX::EndRender()
+{
+ if (m_flags & CAPTUREFLAG_IMMEDIATELY)
+ ReadOut();
+ else
+ SetState(CAPTURESTATE_NEEDSREADOUT);
+}
+
+void* CRenderCaptureIMX::GetRenderBuffer()
+{
+ return m_pixels;
+}
+
+void CRenderCaptureIMX::ReadOut()
+{
+ g_IMXContext.WaitCapture();
+ m_pixels = reinterpret_cast<uint8_t*>(g_IMXContext.GetCaptureBuffer());
+ SetState(CAPTURESTATE_DONE);
+}
+
+#elif defined(TARGET_RASPBERRY_PI)
CRenderCaptureDispmanX::CRenderCaptureDispmanX()
{
diff --git a/xbmc/cores/VideoRenderers/RenderCapture.h b/xbmc/cores/VideoRenderers/RenderCapture.h
index 56d269a..5610945 100644
--- a/xbmc/cores/VideoRenderers/RenderCapture.h
+++ b/xbmc/cores/VideoRenderers/RenderCapture.h
@@ -172,7 +172,33 @@ class CRenderCaptureBase
bool m_asyncChecked;
};
-#if defined(TARGET_RASPBERRY_PI)
+
+#if defined(HAS_IMXVPU)
+#include "../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h"
+
+class CRenderCaptureIMX : public CRenderCaptureBase
+{
+ public:
+ CRenderCaptureIMX();
+ ~CRenderCaptureIMX();
+
+ int GetCaptureFormat();
+
+ void BeginRender();
+ void EndRender();
+ void ReadOut();
+
+ void* GetRenderBuffer();
+};
+
+class CRenderCapture : public CRenderCaptureIMX
+{
+ public:
+ CRenderCapture() {};
+};
+
+
+#elif defined(TARGET_RASPBERRY_PI)
#include "xbmc/linux/RBP.h"
class CRenderCaptureDispmanX : public CRenderCaptureBase
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp
index 65adced..fcd8b02 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp
@@ -45,6 +45,8 @@
// Global instance
CIMXContext g_IMXContext;
+// Number of fb pages used for paning
+const int CIMXContext::m_fbPages = 2;
// 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 = 1+RENDER_QUEUE_SIZE+2;
@@ -435,8 +437,7 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
return false;
}
- if (!g_IMXContext.Configure())
- return false;
+ g_IMXContext.RequireConfiguration();
#ifdef DUMP_STREAM
m_dump = fopen("stream.dump", "wb");
@@ -810,6 +811,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts)
{
goto out_error;
}
+
}
else
{
@@ -882,7 +884,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts)
#endif
#ifdef TRACE_FRAMES
- CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts);
+ CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, dts, pts);
#endif
if (!m_usePTS)
@@ -1269,12 +1271,15 @@ CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer()
CIMXContext::CIMXContext()
: CThread("iMX IPU")
, m_fbHandle(0)
- , m_fbPages(0)
+ , m_fbCurrentPage(0)
, m_fbPhysAddr(0)
, m_fbVirtAddr(NULL)
, m_ipuHandle(0)
, m_vsync(true)
, m_pageCrops(NULL)
+ , m_g2dHandle(NULL)
+ , m_bufferCapture(NULL)
+ , m_checkConfigRequired(true)
{
// Limit queue to 2
m_input.resize(2);
@@ -1286,8 +1291,13 @@ CIMXContext::~CIMXContext()
Close();
}
-bool CIMXContext::Configure(int pages)
+
+bool CIMXContext::Configure()
{
+
+ if (!m_checkConfigRequired)
+ return false;
+
SetBlitRects(CRectInt(), CRectInt());
m_fbCurrentPage = 0;
@@ -1310,17 +1320,7 @@ bool CIMXContext::Configure(int pages)
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;
- }
- }
+ Close();
CLog::Log(LOGNOTICE, "iMX : Initialize render buffers\n");
@@ -1344,14 +1344,20 @@ bool CIMXContext::Configure(int pages)
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');
+ if (m_deInterlacing)
+ {
+ m_fbVar.nonstd = _4CC('U', 'Y', 'V', 'Y');
+ m_fbVar.bits_per_pixel = 16;
+ }
+ else
+ {
+ m_fbVar.nonstd = _4CC('R', 'G', 'B', '4');
+ m_fbVar.bits_per_pixel = 32;
+ }
m_fbVar.activate = FB_ACTIVATE_NOW;
m_fbVar.xres = m_fbWidth;
m_fbVar.yres = m_fbHeight;
@@ -1364,7 +1370,6 @@ bool CIMXContext::Configure(int pages)
CLog::Log(LOGWARNING, "iMX : Failed to setup %s\n", deviceName);
close(m_fbHandle);
m_fbHandle = 0;
- m_fbPages = 0;
return false;
}
@@ -1374,7 +1379,6 @@ bool CIMXContext::Configure(int pages)
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;
}
@@ -1401,6 +1405,7 @@ bool CIMXContext::Configure(int pages)
// Start the ipu thread
Create();
+ m_checkConfigRequired = false;
return true;
}
@@ -1428,7 +1433,6 @@ bool CIMXContext::Close()
{
Blank();
close(m_fbHandle);
- m_fbPages = 0;
m_fbHandle = 0;
m_fbPhysAddr = 0;
}
@@ -1442,7 +1446,8 @@ bool CIMXContext::Close()
m_ipuHandle = 0;
}
- CLog::Log(LOGNOTICE, "iMX : Deinitialized render context\n", m_fbPages);
+ m_checkConfigRequired = true;
+ CLog::Log(LOGNOTICE, "iMX : Deinitialized render context\n");
return true;
}
@@ -1503,7 +1508,14 @@ void CIMXContext::SetInterpolatedFrame(bool flag)
void CIMXContext::SetDeInterlacing(bool flag)
{
+ bool sav_deInt = m_deInterlacing;
m_deInterlacing = flag;
+ // If deinterlacing configuration changes then fb has to be reconfigured
+ if (sav_deInt != m_deInterlacing)
+ {
+ m_checkConfigRequired = true;
+ Configure();
+ }
}
void CIMXContext::SetBlitRects(const CRect &srcRect, const CRect &dstRect)
@@ -1522,10 +1534,18 @@ bool CIMXContext::Blit(int page, CIMXBuffer *source_p, CIMXBuffer *source, bool
return DoTask(ipu, page);
}
-bool CIMXContext::BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source, bool topBottomFields)
+bool CIMXContext::BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source, bool topBottomFields, CRect *dest)
{
IPUTask ipu;
- PrepareTask(ipu, source_p, source, topBottomFields);
+ PrepareTask(ipu, source_p, source, topBottomFields, dest);
+ return PushTask(ipu);
+}
+
+bool CIMXContext::PushCaptureTask(CIMXBuffer *source, CRect *dest)
+{
+ IPUTask ipu;
+ m_CaptureDone = false;
+ PrepareTask(ipu, NULL, source, false, dest);
return PushTask(ipu);
}
@@ -1562,34 +1582,44 @@ void CIMXContext::Clear(int page)
if (!m_fbVirtAddr) return;
uint8_t *tmp_buf;
- int pixels;
+ int bytes;
if (page < 0)
{
tmp_buf = m_fbVirtAddr;
- pixels = m_fbPageSize*m_fbPages/2;
+ bytes = m_fbPageSize*m_fbPages;
}
else if (page < m_fbPages)
{
tmp_buf = m_fbVirtAddr + page*m_fbPageSize;
- pixels = m_fbPageSize/2;
+ bytes = m_fbPageSize;
}
else
// out of range
return;
- for (int i = 0; i < pixels; ++i, tmp_buf += 2)
+
+ if (m_fbVar.nonstd == _4CC('R', 'G', 'B', '4'))
+ memset(tmp_buf, 0, bytes);
+ else if (m_fbVar.nonstd == _4CC('U', 'Y', 'V', 'Y'))
{
- tmp_buf[0] = 128;
- tmp_buf[1] = 16;
+ int pixels = bytes / 2;
+ for (int i = 0; i < pixels; ++i, tmp_buf += 2)
+ {
+ tmp_buf[0] = 128;
+ tmp_buf[1] = 16;
+ }
}
+ else
+ CLog::Log(LOGERROR, "iMX Clear fb error : Unexpected format");
}
#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'))
+ if ((m_fbVar.nonstd != _4CC('R', 'G', 'B', '4')) &&
+ (m_fbVar.nonstd != _4CC('U', 'Y', 'V', 'Y')))
{
CLog::Log(LOGWARNING, "iMX : Unknown screen capture format\n");
return;
@@ -1602,56 +1632,60 @@ void CIMXContext::CaptureDisplay(unsigned char *buffer, int iWidth, int iHeight)
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);
+ if (m_fbVar.nonstd != _4CC('R', 'G', 'B', '4'))
+ memcpy(buffer, display, iWidth * iHeight * 4);
+ else //_4CC('U', 'Y', 'V', 'Y')))
+ {
+ int r,g,b,a;
+ int u, y0, v, y1;
+ int iStride = m_fbWidth*2;
+ int oStride = iWidth*4;
- iWidth = std::min(iWidth/2, m_fbWidth/2);
- iHeight = std::min(iHeight, m_fbHeight);
+ 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);
- for (int y = 0; y < iHeight; ++y, display += iStride, buffer += oStride)
- {
- unsigned char *iLine = display;
- unsigned char *oLine = buffer;
+ iWidth = std::min(iWidth/2, m_fbWidth/2);
+ iHeight = std::min(iHeight, m_fbHeight);
- for (int x = 0; x < iWidth; ++x, iLine += 4, oLine += 8 )
+ for (int y = 0; y < iHeight; ++y, display += iStride, buffer += oStride)
{
- 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;
+ 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;
+ }
}
}
}
@@ -1691,16 +1725,29 @@ bool CIMXContext::PushTask(const IPUTask &task)
return true;
}
+void CIMXContext::WaitCapture()
+{
+ CSingleLock lk(m_monitor);
+ while (!m_CaptureDone)
+ m_inputNotFull.wait(lk);
+}
+
void CIMXContext::PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *source,
- bool topBottomFields)
+ bool topBottomFields, CRect *dest)
{
+ Configure();
// Fill with zeros
ipu.Zero();
ipu.previous = source_p;
ipu.current = source;
CRect srcRect = m_srcRect;
- CRect dstRect = m_dstRect;
+ CRect dstRect;
+ if (dest == NULL)
+ dstRect = m_dstRect;
+ else
+ dstRect = *dest;
+
CRectInt iSrcRect, iDstRect;
float srcWidth = srcRect.Width();
@@ -1754,6 +1801,20 @@ void CIMXContext::PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *so
ipu.task.output.crop.w = iDstRect.Width();
ipu.task.output.crop.h = iDstRect.Height();
+ // If dest is set it means we do not want to blit to frame buffer
+ // but to a capture buffer and we state this capture buffer dimensions
+ if (dest)
+ {
+ // Populate partly output block
+ ipu.task.output.crop.pos.x = 0;
+ ipu.task.output.crop.pos.y = 0;
+ ipu.task.output.crop.w = iDstRect.Width();
+ ipu.task.output.crop.h = iDstRect.Height();
+ ipu.task.output.width = iDstRect.Width();
+ ipu.task.output.height = iDstRect.Height();
+ }
+ else
+ {
// Setup deinterlacing if enabled
if (m_deInterlacing)
{
@@ -1775,6 +1836,7 @@ void CIMXContext::PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *so
else
ipu.task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_BOTTOM;
}
+ }
}
bool CIMXContext::DoTask(IPUTask &ipu, int targetPage)
@@ -1790,16 +1852,40 @@ bool CIMXContext::DoTask(IPUTask &ipu, int targetPage)
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;
+ // Populate output block if it has not already been filled
+ if (ipu.task.output.width == 0)
+ {
+ 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)
+ if (m_pageCrops[targetPage] != dstRect)
+ {
+ m_pageCrops[targetPage] = dstRect;
+ Clear(targetPage);
+ }
+ }
+ else
{
- m_pageCrops[targetPage] = dstRect;
- Clear(targetPage);
+ // If we have already set dest dimensions we want to use capture buffer
+ // Note we allocate this capture buffer as late as this function because
+ // all g2d functions have to be called from the same thread
+ int size = ipu.task.output.width * ipu.task.output.height * 4;
+ if ((m_bufferCapture) && (size != m_bufferCapture->buf_size))
+ {
+ if (g2d_free(m_bufferCapture))
+ CLog::Log(LOGERROR, "iMX : Error while freeing capture buuffer\n");
+ m_bufferCapture = NULL;
+ }
+
+ if (m_bufferCapture == NULL)
+ {
+ m_bufferCapture = g2d_alloc(size, 0);
+ if (m_bufferCapture == NULL)
+ CLog::Log(LOGERROR, "iMX : Error allocating capture buffer\n");
+ }
+ ipu.task.output.paddr = m_bufferCapture->buf_paddr;
}
if ((ipu.task.input.crop.w <= 0) || (ipu.task.input.crop.h <= 0)
@@ -1810,53 +1896,117 @@ bool CIMXContext::DoTask(IPUTask &ipu, int targetPage)
unsigned long long before = XbmcThreads::SystemClockMillis();
#endif
- int ret = IPU_CHECK_ERR_INPUT_CROP;
- while (ret != IPU_CHECK_OK && ret > IPU_CHECK_ERR_MIN)
+ if (ipu.task.input.deinterlace.enable)
{
- ret = ioctl(m_ipuHandle, IPU_CHECK_TASK, &ipu.task);
- switch (ret)
+ //We really use IPU only if we have to deinterlace (using VDIC)
+ int ret = IPU_CHECK_ERR_INPUT_CROP;
+ while (ret != IPU_CHECK_OK && ret > IPU_CHECK_ERR_MIN)
{
- 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);
+ 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;
}
- }
- // 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);
+ // 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);
+ }
+ }
else
- ret = 0;
- ipu.current->EndRender();
-
- if (ret < 0)
{
- CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno));
- return false;
- }
+ // deinterlacing is not required, let's use g2d instead of IPU
- // 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);
+ struct g2d_surface src, dst;
+ memset(&src, 0, sizeof(src));
+ memset(&dst, 0, sizeof(dst));
+
+ ipu.current->BeginRender();
+ if (ipu.current->IsValid())
+ {
+ if (ipu.current->iFormat == _4CC('I', '4', '2', '0'))
+ {
+ src.format = G2D_I420;
+ src.planes[0] = ipu.current->pPhysAddr;
+ src.planes[1] = src.planes[0] + Align(ipu.current->iWidth * ipu.current->iHeight, 64);
+ src.planes[2] = src.planes[1] + Align((ipu.current->iWidth * ipu.current->iHeight) / 2, 64);
+ }
+ else //_4CC('N', 'V', '1', '2');
+ {
+ src.format = G2D_NV12;
+ src.planes[0] = ipu.current->pPhysAddr;
+ src.planes[1] = src.planes[0] + Align(ipu.current->iWidth * ipu.current->iHeight, 64);
+ }
+
+ src.left = ipu.task.input.crop.pos.x;
+ src.right = ipu.task.input.crop.w + src.left ;
+ src.top = ipu.task.input.crop.pos.y;
+ src.bottom = ipu.task.input.crop.h + src.top;
+ src.stride = ipu.current->iWidth;
+ src.width = ipu.current->iWidth;
+ src.height = ipu.current->iHeight;
+ src.rot = G2D_ROTATION_0;
+ /*printf("src planes :%x -%x -%x \n",src.planes[0], src.planes[1], src.planes[2] );
+ printf("src left %d right %d top %d bottom %d stride %d w : %d h %d rot : %d\n",
+ src.left, src.right, src.top, src.bottom, src.stride, src.width, src.height, src.rot);*/
+
+ dst.planes[0] = ipu.task.output.paddr;
+ dst.left = ipu.task.output.crop.pos.x;
+ dst.top = ipu.task.output.crop.pos.y;
+ dst.right = ipu.task.output.crop.w + dst.left;
+ dst.bottom = ipu.task.output.crop.h + dst.top;
+
+ dst.stride = ipu.task.output.width;
+ dst.width = ipu.task.output.width;
+ dst.height = ipu.task.output.height;
+ dst.rot = G2D_ROTATION_0;
+ dst.format = G2D_RGBA8888;
+ /*printf("dst planes :%x -%x -%x \n",dst.planes[0], dst.planes[1], dst.planes[2] );
+ printf("dst left %d right %d top %d bottom %d stride %d w : %d h %d rot : %d format %d\n",
+ dst.left, dst.right, dst.top, dst.bottom, dst.stride, dst.width, dst.height, dst.rot, dst.format);*/
+
+ // Launch synchronous blit
+ g2d_blit(m_g2dHandle, &src, &dst);
+ g2d_finish(m_g2dHandle);
+ if ((m_bufferCapture) && (ipu.task.output.paddr == m_bufferCapture->buf_paddr))
+ m_CaptureDone = true;
+ }
+ ipu.current->EndRender();
}
#ifdef IMX_PROFILE_BUFFERS
@@ -1891,6 +2041,16 @@ void CIMXContext::Process()
bool ret, useBackBuffer;
int backBuffer;
+ // open g2d here to ensure all g2d fucntions are called from the same thread
+ if (m_g2dHandle == NULL)
+ {
+ if (g2d_open(&m_g2dHandle) != 0)
+ {
+ m_g2dHandle = NULL;
+ CLog::Log(LOGERROR, "%s - Error while trying open G2D\n", __FUNCTION__);
+ }
+ }
+
while (!m_bStop)
{
{
@@ -1903,6 +2063,10 @@ void CIMXContext::Process()
useBackBuffer = m_vsync;
IPUTask &task = m_input[m_beginInput];
backBuffer = useBackBuffer?1-m_fbCurrentPage:m_fbCurrentPage;
+
+ // Hack to detect we deal with capture buffer
+ if (task.task.output.width != 0)
+ useBackBuffer = false;
ret = DoTask(task, backBuffer);
// Free resources
@@ -1926,5 +2090,19 @@ void CIMXContext::Process()
--m_bufferedInput;
}
+ // close g2d here to ensure all g2d fucntions are called from the same thread
+ if (m_bufferCapture)
+ {
+ if (g2d_free(m_bufferCapture))
+ CLog::Log(LOGERROR, "iMX : Failed to free capture buffers\n");
+ m_bufferCapture = NULL;
+ }
+ if (m_g2dHandle)
+ {
+ if (g2d_close(m_g2dHandle))
+ CLog::Log(LOGERROR, "iMX : Error while closing G2D\n");
+ m_g2dHandle = NULL;
+ }
+
return;
}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h
index dca3f2f..e414454 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h
@@ -31,6 +31,7 @@
#include <linux/ipu.h>
#include <linux/mxcfb.h>
#include <imx-mm/vpu/vpu_wrapper.h>
+#include <g2d.h>
// The decoding format of the VPU buffer. Comment this to decode
@@ -93,17 +94,15 @@ public:
CIMXContext();
~CIMXContext();
- bool Configure(int pages = 2);
+ void RequireConfiguration() { m_checkConfigRequired = true; }
+ bool Configure();
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; }
+ bool IsValid() const { return m_checkConfigRequired == false; }
// Populates a CIMXBuffer with attributes of a page
bool GetPageInfo(CIMXBuffer *info, int page);
@@ -127,7 +126,7 @@ public:
// been queued. BlitAsync renders always to the current backbuffer and
// swaps the pages.
bool BlitAsync(CIMXBuffer *source_p, CIMXBuffer *source,
- bool topBottomFields = true);
+ bool topBottomFields = true, CRect *dest = NULL);
// Shows a page vsynced
bool ShowPage(int page);
@@ -141,6 +140,9 @@ public:
// 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);
+ bool PushCaptureTask(CIMXBuffer *source, CRect *dest);
+ void *GetCaptureBuffer() const { if (m_bufferCapture) return m_bufferCapture->buf_vaddr; else return NULL; }
+ void WaitCapture();
private:
struct IPUTask
@@ -167,7 +169,7 @@ private:
bool PushTask(const IPUTask &);
void PrepareTask(IPUTask &ipu, CIMXBuffer *source_p, CIMXBuffer *source,
- bool topBottomFields);
+ bool topBottomFields, CRect *dest = NULL);
bool DoTask(IPUTask &ipu, int targetPage);
virtual void OnStartup();
@@ -179,7 +181,6 @@ private:
typedef std::vector<IPUTask> TaskQueue;
int m_fbHandle;
- int m_fbPages;
int m_fbCurrentPage;
int m_fbWidth;
int m_fbHeight;
@@ -206,6 +207,12 @@ private:
XbmcThreads::ConditionVariable m_inputNotEmpty;
XbmcThreads::ConditionVariable m_inputNotFull;
mutable CCriticalSection m_monitor;
+
+ void *m_g2dHandle;
+ struct g2d_buf *m_bufferCapture;
+ bool m_CaptureDone;
+ bool m_checkConfigRequired;
+ static const int m_fbPages;
};
--
1.9.1