mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-24 11:16:51 +00:00
kodi: IMX - implement render capture (wolfgar)
This commit is contained in:
parent
15da75ea4d
commit
ff7d05c3ec
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user