Files
LibreELEC.tv/projects/Cuboxi/patches/xbmc/xbmc-001-imx6_support.patch
Stephan Raue ffb291cf48 projects/Cuboxi/patches/xbmc: update imx patch
Signed-off-by: Stephan Raue <stephan@openelec.tv>
2014-04-13 21:34:19 +02:00

3049 lines
92 KiB
Diff

diff -Naur xbmc-13b3/configure.in xbmc-13b3-imx6/configure.in
--- xbmc-13b3/configure.in 2014-04-13 21:22:52.829923018 +0200
+++ xbmc-13b3-imx6/configure.in 2014-04-13 21:18:33.889476601 +0200
@@ -558,7 +558,7 @@
AC_ARG_ENABLE([codec],
[AS_HELP_STRING([--enable-codec],
- [enable additional codecs from a list of comma separated names, (default is none, choices are amcodec, libstagefright)])],
+ [enable additional codecs from a list of comma separated names, (default is none, choices are amcodec, libstagefright and imxvpu)])],
[add_codecs=$enableval],
[add_codecs=no])
@@ -1034,6 +1034,15 @@
AC_MSG_RESULT($wayland_disabled)
fi
+# i.MX6
+AC_MSG_CHECKING([for i.MX framebuffer support])
+AC_CHECK_HEADER([linux/mxcfb.h], have_imxfb=yes,have_imxfb=no)
+AC_MSG_RESULT($have_imxfb)
+if test "x$have_imxfb" = "xyes"; then
+ AC_DEFINE([HAS_IMXFB], [1], [Whether i.MX framebuffer support is enabled.])
+ AC_SUBST([USE_IMXFB], 1)
+fi
+
# Checks for platforms libraries.
if test "$use_gles" = "yes"; then
use_gl="no"
@@ -1991,6 +2000,17 @@
*libstagefright*)
XB_ADD_CODEC([LIBSTAGEFRIGHT], [libstagefright], [$codecs])
;;
+ *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))
+ XB_ADD_CODEC([IMXVPU], [imxvpu], [$codecs])
+ CXXFLAGS="$CXXFLAGS -Wno-psabi -DLINUX "
+ CFLAGS="$CFLAGS -DLINUX"
+ if test "$use_x11" = "no"; then
+ CXXFLAGS="$CXXFLAGS -DEGL_API_FB"
+ CFLAGS="$CFLAGS -DEGL_API_FB"
+ fi
+ ;;
*)
esac
done
diff -Naur xbmc-13b3/lib/ffmpeg/libavcodec/arm/dca.h xbmc-13b3-imx6/lib/ffmpeg/libavcodec/arm/dca.h
--- xbmc-13b3/lib/ffmpeg/libavcodec/arm/dca.h 2014-04-13 21:22:45.975925014 +0200
+++ xbmc-13b3-imx6/lib/ffmpeg/libavcodec/arm/dca.h 2014-04-13 21:18:34.191477295 +0200
@@ -30,9 +30,9 @@
#define decode_blockcodes decode_blockcodes
static inline int decode_blockcodes(int code1, int code2, int levels,
- int *values)
+ int32_t *values)
{
- int v0, v1, v2, v3, v4, v5;
+ int32_t v0, v1, v2, v3, v4, v5;
__asm__ ("smmul %0, %6, %10 \n"
"smmul %3, %7, %10 \n"
@@ -101,3 +101,4 @@
#endif
#endif /* AVCODEC_ARM_DCA_H */
+
diff -Naur xbmc-13b3/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp xbmc-13b3-imx6/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
--- xbmc-13b3/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp 2014-04-13 21:22:38.977937037 +0200
+++ xbmc-13b3-imx6/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp 2014-04-13 21:18:35.298479839 +0200
@@ -720,7 +720,10 @@
* will automatically add "@" instead to enable surroundXX mangling.
* We don't want to do that if "default" can handle multichannel
* itself (e.g. in case of a pulseaudio server). */
- EnumerateDevice(list, "default", "", config);
+
+ /* For Wandboard, we do not enurate default device as it will be grabbed
+ * as one of the sysdefault devices... */
+
void **hints;
@@ -771,8 +774,8 @@
* found by the enumeration process. Skip them as well ("hw", "dmix",
* "plughw", "dsnoop"). */
+ /* For wandboard all devices are prefixed by sysdefault so do not ignore them */
else if (baseName != "default"
- && baseName != "sysdefault"
&& baseName != "surround40"
&& baseName != "surround41"
&& baseName != "surround50"
@@ -881,6 +884,22 @@
AEDeviceType CAESinkALSA::AEDeviceTypeFromName(const std::string &name)
{
+ std::size_t found;
+
+ /* Hack : Check for specific wandboard sound device names */
+ found = name.find("imxspdif");
+ if (found!=std::string::npos)
+ return AE_DEVTYPE_IEC958;
+
+ found = name.find("imxhdmisoc");
+ if (found!=std::string::npos)
+ return AE_DEVTYPE_HDMI;
+
+ found = name.find("sgtl5000audio");
+ if (found!=std::string::npos)
+ return AE_DEVTYPE_PCM;
+
+
if (name.substr(0, 4) == "hdmi")
return AE_DEVTYPE_HDMI;
else if (name.substr(0, 6) == "iec958" || name.substr(0, 5) == "spdif")
diff -Naur xbmc-13b3/xbmc/cores/AudioEngine/Utils/AEConvert.cpp xbmc-13b3-imx6/xbmc/cores/AudioEngine/Utils/AEConvert.cpp
--- xbmc-13b3/xbmc/cores/AudioEngine/Utils/AEConvert.cpp 2014-04-13 21:22:39.007936966 +0200
+++ xbmc-13b3-imx6/xbmc/cores/AudioEngine/Utils/AEConvert.cpp 2014-04-13 21:18:35.320479890 +0200
@@ -841,7 +841,7 @@
_mm_empty();
#else /* no SSE2 */
for (uint32_t i = 0; i < samples; ++i)
- *dst++ = (safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8;
+ *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0x00FFFFFF;
#endif
return samples << 2;
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp 2014-04-13 21:22:38.682937885 +0200
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp 2014-04-13 21:18:35.416480110 +0200
@@ -35,6 +35,9 @@
#include "Video/DVDVideoCodecFFmpeg.h"
#include "Video/DVDVideoCodecOpenMax.h"
#include "Video/DVDVideoCodecLibMpeg2.h"
+#if defined(HAS_IMXVPU)
+#include "Video/DVDVideoCodecIMX.h"
+#endif
#include "Video/DVDVideoCodecStageFright.h"
#if defined(HAVE_LIBCRYSTALHD)
#include "Video/DVDVideoCodecCrystalHD.h"
@@ -191,7 +194,11 @@
#elif defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
hwSupport += "VAAPI:no ";
#endif
-
+#if defined(HAS_IMXVPU)
+ hwSupport += "iMXVPU:yes ";
+#else
+ hwSupport += "iMXVPU:no ";
+#endif
CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
#if defined(HAS_LIBAMCODEC)
// amcodec can handle dvd playback.
@@ -205,6 +212,15 @@
}
}
+/*#endif*/
+
+#if defined(HAS_IMXVPU)
+ if (!hint.software)
+ {
+ if ( (pCodec = OpenCodec(new CDVDVideoCodecIMX(), hint, options)) ) return pCodec;
+ }
+#endif
+
#if defined(TARGET_DARWIN_OSX)
if (!hint.software && CSettings::Get().GetBool("videoplayer.usevda"))
{
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2014-04-13 21:22:38.733937740 +0200
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2014-04-13 21:18:35.424480129 +0200
@@ -27,6 +27,7 @@
#include <vector>
#include <string>
#include "cores/VideoRenderers/RenderFormats.h"
+#include "DVDVideoCodecInfo.h"
struct DVDCodecAvailableType
{
@@ -91,6 +92,11 @@
struct {
CDVDMediaCodecInfo *mediacodec;
};
+
+ struct {
+ CDVDVideoCodecBuffer *codecinfo;
+ };
+
};
unsigned int iFlags;
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp 1970-01-01 01:00:00.000000000 +0100
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp 2014-04-13 21:18:35.425480131 +0200
@@ -0,0 +1,1501 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "DVDVideoCodecIMX.h"
+
+#include <sys/stat.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/mxcfb.h>
+#include <linux/ipu.h>
+#include "threads/SingleLock.h"
+#include "utils/log.h"
+#include "DVDClock.h"
+#include "threads/Atomics.h"
+
+
+// FIXME get rid of these defines properly
+#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))
+#define Align(ptr,align) (((unsigned int)ptr + (align) - 1)/(align)*(align))
+
+// Extrace physical and virtual addresses from CDVDVideoCodecBuffer pointers
+#define GET_PHYS_ADDR(buf) (buf)->data[1]
+#define GET_VIRT_ADDR(buf) (buf)->data[0]
+#define GET_DEINTERLACER(buf) (buf)->data[2]
+#define GET_FIELDTYPE(buf) (buf)->data[3]
+
+// Experiments show that we need at least one more (+1) V4L 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)
+{
+ int i, size;
+ void* ptr;
+ VpuMemDesc vpuMem;
+ VpuDecRetCode ret;
+
+ for(i=0; i<pMemBlock->nSubBlockNum; i++)
+ {
+ size = pMemBlock->MemSubBlock[i].nAlignment + pMemBlock->MemSubBlock[i].nSize;
+ if (pMemBlock->MemSubBlock[i].MemType == VPU_MEM_VIRT)
+ { // Allocate standard virtual memory
+ ptr = malloc(size);
+ if(ptr == NULL)
+ {
+ CLog::Log(LOGERROR, "%s - Unable to malloc %d bytes.\n", __FUNCTION__, size);
+ goto AllocFailure;
+ }
+ pMemBlock->MemSubBlock[i].pVirtAddr = (unsigned char*)Align(ptr, pMemBlock->MemSubBlock[i].nAlignment);
+
+ m_decMemInfo.nVirtNum++;
+ m_decMemInfo.virtMem = (void**)realloc(m_decMemInfo.virtMem, m_decMemInfo.nVirtNum*sizeof(void*));
+ m_decMemInfo.virtMem[m_decMemInfo.nVirtNum-1] = ptr;
+ }
+ else
+ { // Allocate contigous mem for DMA
+ vpuMem.nSize = size;
+ ret = VPU_DecGetMem(&vpuMem);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - Unable alloc %d bytes of physical memory (%d).\n", __FUNCTION__, size, ret);
+ goto AllocFailure;
+ }
+ pMemBlock->MemSubBlock[i].pVirtAddr = (unsigned char*)Align(vpuMem.nVirtAddr, pMemBlock->MemSubBlock[i].nAlignment);
+ pMemBlock->MemSubBlock[i].pPhyAddr = (unsigned char*)Align(vpuMem.nPhyAddr, pMemBlock->MemSubBlock[i].nAlignment);
+
+ m_decMemInfo.nPhyNum++;
+ m_decMemInfo.phyMem = (VpuMemDesc*)realloc(m_decMemInfo.phyMem, m_decMemInfo.nPhyNum*sizeof(VpuMemDesc));
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nPhyAddr = vpuMem.nPhyAddr;
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nVirtAddr = vpuMem.nVirtAddr;
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nCpuAddr = vpuMem.nCpuAddr;
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nSize = size;
+ }
+ }
+
+ return true;
+
+AllocFailure:
+ VpuFreeBuffers();
+ return false;
+}
+
+int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr)
+{
+ for (int i=0; i<m_vpuFrameBufferNum; i++)
+ {
+ if (m_vpuFrameBuffers[i].pbufY == frameAddr)
+ return i;
+ }
+ return -1;
+}
+
+bool CDVDVideoCodecIMX::VpuFreeBuffers(void)
+{
+ VpuMemDesc vpuMem;
+ VpuDecRetCode vpuRet;
+ bool ret = true;
+
+ if (m_decMemInfo.virtMem)
+ {
+ //free virtual mem
+ for(int i=0; i<m_decMemInfo.nVirtNum; i++)
+ {
+ if (m_decMemInfo.virtMem[i])
+ free((void*)m_decMemInfo.virtMem[i]);
+ }
+ free(m_decMemInfo.virtMem);
+ m_decMemInfo.virtMem = NULL;
+ m_decMemInfo.nVirtNum = 0;
+ }
+
+ if (m_decMemInfo.phyMem)
+ {
+ //free physical mem
+ for(int i=0; i<m_decMemInfo.nPhyNum; i++)
+ {
+ vpuMem.nPhyAddr = m_decMemInfo.phyMem[i].nPhyAddr;
+ vpuMem.nVirtAddr = m_decMemInfo.phyMem[i].nVirtAddr;
+ vpuMem.nCpuAddr = m_decMemInfo.phyMem[i].nCpuAddr;
+ vpuMem.nSize = m_decMemInfo.phyMem[i].nSize;
+ vpuRet = VPU_DecFreeMem(&vpuMem);
+ if(vpuRet != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - Errror while trying to free physical memory (%d).\n", __FUNCTION__, ret);
+ ret = false;
+ }
+ }
+ free(m_decMemInfo.phyMem);
+ m_decMemInfo.phyMem = NULL;
+ m_decMemInfo.nPhyNum = 0;
+ }
+
+ return ret;
+}
+
+
+bool CDVDVideoCodecIMX::VpuOpen(void)
+{
+ VpuDecRetCode ret;
+ VpuVersionInfo vpuVersion;
+ VpuMemInfo memInfo;
+ VpuDecConfig config;
+ int param;
+
+ memset(&memInfo, 0, sizeof(VpuMemInfo));
+ ret = VPU_DecLoad();
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU load failed with error code %d.\n", __FUNCTION__, ret);
+ goto VpuOpenError;
+ }
+
+ ret = VPU_DecGetVersionInfo(&vpuVersion);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU version cannot be read (%d).\n", __FUNCTION__, ret);
+ goto VpuOpenError;
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "VPU Lib version : major.minor.rel=%d.%d.%d.\n", vpuVersion.nLibMajor, vpuVersion.nLibMinor, vpuVersion.nLibRelease);
+ }
+
+ ret = VPU_DecQueryMem(&memInfo);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - iMX VPU query mem error (%d).\n", __FUNCTION__, ret);
+ goto VpuOpenError;
+ }
+ VpuAllocBuffers(&memInfo);
+
+ m_decOpenParam.nReorderEnable = 1;
+ m_decOpenParam.nChromaInterleave = 1;
+ m_decOpenParam.nMapType = 0;
+ m_decOpenParam.nTiled2LinearEnable = 0;
+ m_decOpenParam.nEnableFileMode = 0;
+
+ ret = VPU_DecOpen(&m_vpuHandle, &m_decOpenParam, &memInfo);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - iMX VPU open failed (%d).\n", __FUNCTION__, ret);
+ goto VpuOpenError;
+ }
+
+ config = VPU_DEC_CONF_SKIPMODE;
+ param = VPU_DEC_SKIPNONE;
+ ret = VPU_DecConfig(m_vpuHandle, config, &param);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - iMX VPU set skip mode 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
+ // naming is misleading...
+ ret = VPU_DecGetCapability(m_vpuHandle, VPU_DEC_CAP_FRAMESIZE, &param);
+ m_frameReported = (param != 0);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - iMX VPU get framesize capability failed (%d).\n", __FUNCTION__, ret);
+ m_frameReported = false;
+ }
+
+ return true;
+
+VpuOpenError:
+ Dispose();
+ return false;
+}
+
+bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void)
+{
+ 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_vpuFrameBuffers = new VpuFrameBuffer[m_vpuFrameBufferNum];
+
+ 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));
+ }
+ else
+ {
+ ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN);
+ }
+
+ //NV12 for all video
+ uvStride=yStride;
+ uvSize=ySize/2;
+ mvSize=uvSize/2;
+
+ nAlign=m_initInfo.nAddressAlignment;
+ if(nAlign>1)
+ {
+ ySize=Align(ySize,nAlign);
+ uvSize=Align(uvSize,nAlign);
+ }
+
+ m_outputBuffers = new CDVDVideoCodecIMXBuffer*[m_vpuFrameBufferNum];
+
+ for (int i=0 ; i < m_vpuFrameBufferNum; i++)
+ {
+ totalSize=(ySize+uvSize+mvSize+nAlign)*1;
+
+ vpuMem.nSize=totalSize;
+ ret = VPU_DecGetMem(&vpuMem);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s: vpu malloc frame buf failure: ret=%d \r\n",__FUNCTION__,ret);
+ return false;
+ }
+
+ //record memory info for release
+ m_decMemInfo.nPhyNum++;
+ m_decMemInfo.phyMem = (VpuMemDesc*)realloc(m_decMemInfo.phyMem, m_decMemInfo.nPhyNum*sizeof(VpuMemDesc));
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nPhyAddr = vpuMem.nPhyAddr;
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nVirtAddr = vpuMem.nVirtAddr;
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nCpuAddr = vpuMem.nCpuAddr;
+ m_decMemInfo.phyMem[m_decMemInfo.nPhyNum-1].nSize = vpuMem.nSize;
+
+ //fill frameBuf
+ 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);
+ }
+
+ // fill stride info
+ 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;
+ //ptr+=ySize+uSize+vSize+mvSize;
+ // 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;
+ //ptrVirt+=ySize+uSize+vSize+mvSize;
+
+ m_vpuFrameBuffers[i].pbufY_tilebot=0;
+ m_vpuFrameBuffers[i].pbufCb_tilebot=0;
+ m_vpuFrameBuffers[i].pbufVirtY_tilebot=0;
+ m_vpuFrameBuffers[i].pbufVirtCb_tilebot=0;
+
+#ifdef TRACE_FRAMES
+ m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer(i);
+#else
+ m_outputBuffers[i] = new CDVDVideoCodecIMXBuffer();
+#endif
+ }
+
+ if (m_initInfo.nInterlace)
+ {
+ CLog::Log(LOGNOTICE, "IMX: Enable hardware deinterlacing\n");
+ if (!m_deinterlacer.Init(m_initInfo.nPicWidth, m_initInfo.nPicHeight, GetAllowedReferences()+1, nAlign))
+ {
+ CLog::Log(LOGWARNING, "IMX: Failed to initialize IPU buffers: deinterlacing disabled\n");
+ }
+ else
+ {
+ for (int i=0; i<m_vpuFrameBufferNum; i++)
+ GET_DEINTERLACER(m_outputBuffers[i]) = (uint8_t*)&m_deinterlacer;
+ }
+ }
+
+ return true;
+}
+
+CDVDVideoCodecIMX::CDVDVideoCodecIMX()
+{
+ m_pFormatName = "iMX-xxx";
+ m_vpuHandle = 0;
+ m_vpuFrameBuffers = NULL;
+ m_outputBuffers = NULL;
+ m_lastBuffer = NULL;
+ m_extraMem = NULL;
+ m_vpuFrameBufferNum = 0;
+ m_dropState = false;
+ m_convert_bitstream = false;
+ m_frameCounter = 0;
+ m_usePTS = true;
+ if (getenv("IMX_NOPTS") != NULL)
+ {
+ m_usePTS = false;
+ }
+ m_converter = NULL;
+ m_convert_bitstream = false;
+ m_bytesToBeConsumed = 0;
+ m_previousPts = DVD_NOPTS_VALUE;
+}
+
+CDVDVideoCodecIMX::~CDVDVideoCodecIMX()
+{
+ Dispose();
+}
+
+bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
+{
+ if (hints.software)
+ {
+ CLog::Log(LOGNOTICE, "iMX VPU : software decoding requested.\n");
+ return false;
+ }
+
+ m_hints = hints;
+ CLog::Log(LOGDEBUG, "Let's decode with iMX VPU\n");
+
+#ifdef MEDIAINFO
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: fpsrate %d / fpsscale %d\n", m_hints.fpsrate, m_hints.fpsscale);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: CodecID %d \n", m_hints.codec);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: StreamType %d \n", m_hints.type);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Level %d \n", m_hints.level);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Profile %d \n", m_hints.profile);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: PTS_invalid %d \n", m_hints.ptsinvalid);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Tag %d \n", m_hints.codec_tag);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: %dx%d \n", m_hints.width, m_hints.height);
+ { uint8_t *pb = (uint8_t*)&m_hints.codec_tag;
+ if (isalnum(pb[0]) && isalnum(pb[1]) && isalnum(pb[2]) && isalnum(pb[3]))
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: Tag fourcc %c%c%c%c\n", pb[0], pb[1], pb[2], pb[3]);
+ }
+ if (m_hints.extrasize)
+ {
+ char buf[4096];
+
+ for (unsigned int i=0; i < m_hints.extrasize; i++)
+ sprintf(buf+i*2, "%02x", ((uint8_t*)m_hints.extradata)[i]);
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: extradata %d %s\n", m_hints.extrasize, buf);
+ }
+ CLog::Log(LOGDEBUG, "Decode: MEDIAINFO: %d / %d \n", m_hints.width, m_hints.height);
+ CLog::Log(LOGDEBUG, "Decode: aspect %f - forced aspect %d\n", m_hints.aspect, m_hints.forced_aspect);
+#endif
+
+ m_convert_bitstream = false;
+ switch(m_hints.codec)
+ {
+ case CODEC_ID_MPEG1VIDEO:
+ m_decOpenParam.CodecFormat = VPU_V_MPEG2;
+ m_pFormatName = "iMX-mpeg1";
+ break;
+ case CODEC_ID_MPEG2VIDEO:
+ case CODEC_ID_MPEG2VIDEO_XVMC:
+ m_decOpenParam.CodecFormat = VPU_V_MPEG2;
+ m_pFormatName = "iMX-mpeg2";
+ break;
+ case CODEC_ID_H263:
+ m_decOpenParam.CodecFormat = VPU_V_H263;
+ m_pFormatName = "iMX-h263";
+ break;
+ case CODEC_ID_H264:
+ if (m_hints.profile == 110)
+ {
+ CLog::Log(LOGNOTICE, "i.MX6 VPU is not able to decode AVC high 10 profile\n");
+ return false;
+ }
+ m_decOpenParam.CodecFormat = VPU_V_AVC;
+ m_pFormatName = "iMX-h264";
+ if (hints.extradata)
+ {
+ if ( *(char*)hints.extradata == 1 )
+ {
+ m_converter = new CBitstreamConverter();
+ m_convert_bitstream = m_converter->Open(hints.codec, (uint8_t *)hints.extradata, hints.extrasize, true);
+ }
+ }
+ break;
+ case CODEC_ID_VC1:
+ m_decOpenParam.CodecFormat = VPU_V_VC1_AP;
+ m_pFormatName = "iMX-vc1";
+ break;
+/* FIXME TODO
+ * => for this type we have to set height, width, nChromaInterleave and nMapType
+ case CODEC_ID_MJPEG:
+ m_decOpenParam.CodecFormat = VPU_V_MJPG;
+ m_pFormatName = "iMX-mjpg";
+ break;*/
+ case CODEC_ID_CAVS:
+ case CODEC_ID_AVS:
+ m_decOpenParam.CodecFormat = VPU_V_AVS;
+ m_pFormatName = "iMX-AVS";
+ break;
+ case CODEC_ID_RV10:
+ case CODEC_ID_RV20:
+ case CODEC_ID_RV30:
+ case CODEC_ID_RV40:
+ m_decOpenParam.CodecFormat = VPU_V_RV;
+ m_pFormatName = "iMX-RV";
+ break;
+ case CODEC_ID_KMVC:
+ m_decOpenParam.CodecFormat = VPU_V_AVC_MVC;
+ m_pFormatName = "iMX-MVC";
+ break;
+ case CODEC_ID_VP8:
+ m_decOpenParam.CodecFormat = VPU_V_VP8;
+ m_pFormatName = "iMX-vp8";
+ break;
+ case CODEC_ID_MPEG4:
+ switch(m_hints.codec_tag)
+ {
+ case _4CC('D','I','V','X'):
+ m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX4
+ m_pFormatName = "iMX-divx4";
+ break;
+ case _4CC('D','X','5','0'):
+ case _4CC('D','I','V','5'):
+ m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX56
+ m_pFormatName = "iMX-divx5";
+ break;
+ case _4CC('X','V','I','D'):
+ case _4CC('M','P','4','V'):
+ case _4CC('P','M','P','4'):
+ case _4CC('F','M','P','4'):
+ m_decOpenParam.CodecFormat = VPU_V_XVID;
+ m_pFormatName = "iMX-xvid";
+ break;
+ default:
+ CLog::Log(LOGERROR, "iMX VPU : MPEG4 codec tag %d is not (yet) handled.\n", m_hints.codec_tag);
+ return false;
+ }
+ break;
+ default:
+ CLog::Log(LOGERROR, "iMX VPU : codecid %d is not (yet) handled.\n", m_hints.codec);
+ return false;
+ }
+
+ return true;
+}
+
+void CDVDVideoCodecIMX::Dispose(void)
+{
+ VpuDecRetCode ret;
+ bool VPU_loaded = m_vpuHandle;
+
+ // Block render thread from using that framebuffers
+ Enter();
+
+ // Release last buffer
+ if(m_lastBuffer)
+ SAFE_RELEASE(m_lastBuffer);
+
+ // Invalidate output buffers to prevent the renderer from mapping this memory
+ for (int i=0; i<m_vpuFrameBufferNum; i++)
+ {
+ m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle);
+ SAFE_RELEASE(m_outputBuffers[i]);
+ }
+
+ Leave();
+
+ if (m_vpuHandle)
+ {
+ ret = VPU_DecFlushAll(m_vpuHandle);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU flush failed with error code %d.\n", __FUNCTION__, ret);
+ }
+ ret = VPU_DecClose(m_vpuHandle);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU close failed with error code %d.\n", __FUNCTION__, ret);
+ }
+ m_vpuHandle = 0;
+ }
+
+ m_frameCounter = 0;
+ m_deinterlacer.Close();
+
+ // Clear memory
+ if (m_outputBuffers != NULL)
+ {
+ delete m_outputBuffers;
+ m_outputBuffers = NULL;
+ }
+
+ VpuFreeBuffers();
+ m_vpuFrameBufferNum = 0;
+
+ if (m_vpuFrameBuffers != NULL)
+ {
+ delete m_vpuFrameBuffers;
+ m_vpuFrameBuffers = NULL;
+ }
+
+ if (VPU_loaded)
+ {
+ ret = VPU_DecUnLoad();
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU unload failed with error code %d.\n", __FUNCTION__, ret);
+ }
+ }
+
+ if (m_converter)
+ {
+ m_converter->Close();
+ SAFE_DELETE(m_converter);
+ }
+ return;
+}
+
+int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts)
+{
+ VpuDecFrameLengthInfo frameLengthInfo;
+ VpuBufferNode inData;
+ VpuDecRetCode ret;
+ int decRet = 0;
+ int retStatus = 0;
+ int demuxer_bytes = iSize;
+ uint8_t *demuxer_content = pData;
+ int retries = 0;
+ int idx;
+
+#ifdef IMX_PROFILE
+ static unsigned long long previous, current;
+ unsigned long long before_dec;
+#endif
+
+ if (!m_vpuHandle)
+ {
+ VpuOpen();
+ if (!m_vpuHandle)
+ return VC_ERROR;
+ }
+
+ for (int i=0; i < m_vpuFrameBufferNum; i++)
+ {
+ if (m_outputBuffers[i]->Rendered())
+ {
+ ret = m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret);
+ }
+ }
+ }
+
+#ifdef IMX_PROFILE
+ current = XbmcThreads::SystemClockMillis();
+ CLog::Log(LOGDEBUG, "%s - delta time decode : %llu - demux size : %d dts : %f - pts : %f\n", __FUNCTION__, current - previous, iSize, dts, pts);
+ previous = current;
+#endif
+
+ if ((pData && iSize) ||
+ (m_bytesToBeConsumed))
+ {
+ if ((m_convert_bitstream) && (iSize))
+ {
+ // convert demuxer packet from bitstream to bytestream (AnnexB)
+ if (m_converter->Convert(demuxer_content, demuxer_bytes))
+ {
+ demuxer_content = m_converter->GetConvertBuffer();
+ demuxer_bytes = m_converter->GetConvertSize();
+ }
+ else
+ CLog::Log(LOGERROR,"%s - bitstream_convert error", __FUNCTION__);
+ }
+
+ inData.nSize = demuxer_bytes;
+ inData.pPhyAddr = NULL;
+ inData.pVirAddr = demuxer_content;
+ // FIXME TODO VP8 & DivX3 require specific sCodecData values
+ if ((m_decOpenParam.CodecFormat == VPU_V_MPEG2) ||
+ (m_decOpenParam.CodecFormat == VPU_V_VC1_AP)||
+ (m_decOpenParam.CodecFormat == VPU_V_XVID))
+ {
+ inData.sCodecData.pData = (unsigned char *)m_hints.extradata;
+ inData.sCodecData.nSize = m_hints.extrasize;
+ }
+ else
+ {
+ inData.sCodecData.pData = NULL;
+ inData.sCodecData.nSize = 0;
+ }
+
+ while (true) // Decode as long as the VPU consumes data
+ {
+#ifdef IMX_PROFILE
+ before_dec = XbmcThreads::SystemClockMillis();
+#endif
+ if (m_frameReported)
+ 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);
+#endif
+
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU decode failed with error code %d.\n", __FUNCTION__, ret);
+ goto out_error;
+ }
+
+ if (decRet & VPU_DEC_INIT_OK)
+ // VPU decoding init OK : We can retrieve stream info
+ {
+ ret = VPU_DecGetInitialInfo(m_vpuHandle, &m_initInfo);
+ if (ret == VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGDEBUG, "%s - VPU Init Stream Info : %dx%d (interlaced : %d - Minframe : %d)"\
+ " - Align : %d bytes - crop : %d %d %d %d - Q16Ratio : %x\n", __FUNCTION__,
+ m_initInfo.nPicWidth, m_initInfo.nPicHeight, m_initInfo.nInterlace, m_initInfo.nMinFrameBufferCount,
+ m_initInfo.nAddressAlignment, m_initInfo.PicCropRect.nLeft, m_initInfo.PicCropRect.nTop,
+ m_initInfo.PicCropRect.nRight, m_initInfo.PicCropRect.nBottom, m_initInfo.nQ16ShiftWidthDivHeightRatio);
+ if (VpuAllocFrameBuffers())
+ {
+ ret = VPU_DecRegisterFrameBuffer(m_vpuHandle, m_vpuFrameBuffers, m_vpuFrameBufferNum);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU error while registering frame buffers (%d).\n", __FUNCTION__, ret);
+ goto out_error;
+ }
+ }
+ else
+ {
+ goto out_error;
+ }
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "%s - VPU get initial info failed (%d).\n", __FUNCTION__, ret);
+ goto out_error;
+ }
+ } //VPU_DEC_INIT_OK
+
+ if (decRet & VPU_DEC_ONE_FRM_CONSUMED)
+ {
+ ret = VPU_DecGetConsumedFrameInfo(m_vpuHandle, &frameLengthInfo);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU error retireving info about consummed frame (%d).\n", __FUNCTION__, ret);
+ }
+ m_bytesToBeConsumed -= (frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength);
+ if (frameLengthInfo.pFrame)
+ {
+ idx = VpuFindBuffer(frameLengthInfo.pFrame->pbufY);
+ if (m_bytesToBeConsumed < 50)
+ m_bytesToBeConsumed = 0;
+ if (idx != -1)
+ {
+ if (m_previousPts != DVD_NOPTS_VALUE)
+ {
+ m_outputBuffers[idx]->SetPts(m_previousPts);
+ m_previousPts = DVD_NOPTS_VALUE;
+ }
+ else
+ m_outputBuffers[idx]->SetPts(pts);
+ }
+ else
+ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__);
+ }
+ } //VPU_DEC_ONE_FRM_CONSUMED
+
+ if (decRet & VPU_DEC_OUTPUT_DIS)
+ // Frame ready to be displayed
+ {
+ if (retStatus & VC_PICTURE)
+ CLog::Log(LOGERROR, "%s - Second picture in the same decode call !\n", __FUNCTION__);
+
+ ret = VPU_DecGetOutputFrame(m_vpuHandle, &m_frameInfo);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret);
+ goto out_error;
+ }
+
+ // Some codecs (VC1?) lie about their frame size (mod 16). Adjust...
+ m_frameInfo.pExtInfo->nFrmWidth = (((m_frameInfo.pExtInfo->nFrmWidth) + 15) & ~15);
+ m_frameInfo.pExtInfo->nFrmHeight = (((m_frameInfo.pExtInfo->nFrmHeight) + 15) & ~15);
+
+ retStatus |= VC_PICTURE;
+ } //VPU_DEC_OUTPUT_DIS
+
+ // According to libfslvpuwrap: If this flag is set then the frame should
+ // be dropped. It is just returned to gather decoder information but not
+ // for display.
+ if (decRet & VPU_DEC_OUTPUT_MOSAIC_DIS)
+ {
+ ret = VPU_DecGetOutputFrame(m_vpuHandle, &m_frameInfo);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret);
+ goto out_error;
+ }
+
+ // Display frame
+ ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s: VPU Clear frame display failure(%d)\n",__FUNCTION__,ret);
+ goto out_error;
+ }
+ } //VPU_DEC_OUTPUT_MOSAIC_DIS
+
+ if (decRet & VPU_DEC_OUTPUT_REPEAT)
+ {
+ CLog::Log(LOGDEBUG, "%s - Frame repeat.\n", __FUNCTION__);
+ }
+ if (decRet & VPU_DEC_OUTPUT_DROPPED)
+ {
+ CLog::Log(LOGDEBUG, "%s - Frame dropped.\n", __FUNCTION__);
+ }
+ if (decRet & VPU_DEC_NO_ENOUGH_BUF)
+ {
+ CLog::Log(LOGERROR, "%s - No frame buffer available.\n", __FUNCTION__);
+ }
+ if (decRet & VPU_DEC_SKIP)
+ {
+ CLog::Log(LOGDEBUG, "%s - Frame skipped.\n", __FUNCTION__);
+ }
+ if (decRet & VPU_DEC_FLUSH)
+ {
+ CLog::Log(LOGNOTICE, "%s - VPU requires a flush.\n", __FUNCTION__);
+ Reset();
+ retStatus = VC_FLUSHED;
+ }
+ if (decRet & VPU_DEC_OUTPUT_EOS)
+ {
+ CLog::Log(LOGNOTICE, "%s - EOS encountered.\n", __FUNCTION__);
+ }
+ if ((decRet & VPU_DEC_NO_ENOUGH_INBUF) ||
+ (decRet & VPU_DEC_OUTPUT_DIS))
+ {
+ // We are done with VPU decoder that time
+ break;
+ }
+
+ retries++;
+ if (retries >= m_maxVpuDecodeLoops)
+ {
+ CLog::Log(LOGERROR, "%s - Leaving VPU decoding loop after %d iterations\n", __FUNCTION__, m_maxVpuDecodeLoops);
+ break;
+ }
+
+ if (!(decRet & VPU_DEC_INPUT_USED))
+ {
+ CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize);
+ }
+
+ // Let's process again as VPU_DEC_NO_ENOUGH_INBUF was not set
+ // and we don't have an image ready if we reach that point
+ inData.pVirAddr = NULL;
+ inData.nSize = 0;
+ } // Decode loop
+ } //(pData && iSize)
+
+ if (retStatus == 0)
+ {
+ retStatus |= VC_BUFFER;
+ }
+
+ if (m_bytesToBeConsumed > 0)
+ {
+ // Remember the current pts because the data which has just
+ // been sent to the VPU has not yet been consumed.
+ // This pts is related to the frame that will be consumed
+ // 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);
+#endif
+ return retStatus;
+
+out_error:
+ return VC_ERROR;
+}
+
+void CDVDVideoCodecIMX::Reset()
+{
+ int ret;
+
+ CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__);
+
+ // Release last buffer
+ if(m_lastBuffer)
+ SAFE_RELEASE(m_lastBuffer);
+
+ // Invalidate all buffers
+ for(int i=0; i < m_vpuFrameBufferNum; i++)
+ m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle);
+
+ m_frameCounter = 0;
+ m_deinterlacer.Reset();
+ m_bytesToBeConsumed = 0;
+ m_previousPts = DVD_NOPTS_VALUE;
+
+ // Flush VPU
+ ret = VPU_DecFlushAll(m_vpuHandle);
+ if (ret != VPU_DEC_RET_SUCCESS)
+ {
+ CLog::Log(LOGERROR, "%s - VPU flush failed with error code %d.\n", __FUNCTION__, ret);
+ }
+
+}
+
+unsigned CDVDVideoCodecIMX::GetAllowedReferences()
+{
+ return 3;
+}
+
+bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
+{
+ if (pDvdVideoPicture)
+ {
+ SAFE_RELEASE(pDvdVideoPicture->codecinfo);
+ }
+
+ return true;
+}
+
+bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture)
+{
+#ifdef IMX_PROFILE
+ static unsigned int previous = 0;
+ unsigned int current;
+
+ current = XbmcThreads::SystemClockMillis();
+ CLog::Log(LOGDEBUG, "%s tm:%03d\n", __FUNCTION__, current - previous);
+ previous = current;
+#endif
+
+ m_frameCounter++;
+
+ pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
+ if (m_dropState)
+ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
+ else
+ pDvdVideoPicture->iFlags &= ~DVP_FLAG_DROPPED;
+
+ pDvdVideoPicture->format = RENDER_FMT_IMXMAP;
+ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
+ pDvdVideoPicture->iWidth = m_frameInfo.pExtInfo->FrmCropRect.nRight - m_frameInfo.pExtInfo->FrmCropRect.nLeft;
+ pDvdVideoPicture->iHeight = m_frameInfo.pExtInfo->FrmCropRect.nBottom - m_frameInfo.pExtInfo->FrmCropRect.nTop;
+
+ pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16;
+ pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight;
+
+ int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY);
+ if (idx != -1)
+ {
+ CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx];
+
+ pDvdVideoPicture->pts = buffer->GetPts();
+ pDvdVideoPicture->dts = m_dts;
+ if (!m_usePTS)
+ {
+ pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
+ pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
+ }
+
+ 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
+
+ /*
+ // This does not work reliably since some streams do not report
+ // correctly if a frame is interlaced.
+ if (m_frameInfo.eFieldType != VPU_FIELD_NONE)
+ GET_DEINTERLACER(buffer) = (uint8_t*)&m_deinterlacer;
+ else
+ GET_DEINTERLACER(buffer) = NULL;
+ */
+
+ pDvdVideoPicture->codecinfo = buffer;
+ pDvdVideoPicture->codecinfo->Lock();
+
+ // Save last buffer
+ if (m_lastBuffer)
+ SAFE_RELEASE(m_lastBuffer);
+
+ m_lastBuffer = buffer;
+ m_lastBuffer->Lock();
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__);
+ }
+
+ return true;
+}
+
+void CDVDVideoCodecIMX::SetDropState(bool bDrop)
+{
+
+ // We are fast enough to continue to really decode every frames
+ // and avoid artefacts...
+ // (Of course these frames won't be rendered but only decoded !)
+
+ if (m_dropState != bDrop)
+ {
+ m_dropState = bDrop;
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "%s : %d\n", __FUNCTION__, bDrop);
+#endif
+ }
+}
+
+void CDVDVideoCodecIMX::Enter()
+{
+ m_codecBufferLock.lock();
+}
+
+void CDVDVideoCodecIMX::Leave()
+{
+ m_codecBufferLock.unlock();
+}
+
+/*******************************************/
+
+#ifdef TRACE_FRAMES
+CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx)
+ : m_refs(1)
+ , m_idx(idx)
+#else
+CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer()
+ : m_refs(1)
+#endif
+ , m_frameBuffer(NULL)
+ , m_rendered(false)
+ , m_pts(DVD_NOPTS_VALUE)
+ , m_previousBuffer(NULL)
+{
+ GET_DEINTERLACER(this) = NULL;
+}
+
+void CDVDVideoCodecIMXBuffer::Lock()
+{
+#ifdef TRACE_FRAMES
+ long count = AtomicIncrement(&m_refs);
+ CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (VPU)\n", m_idx, count);
+#else
+ AtomicIncrement(&m_refs);
+#endif
+}
+
+long CDVDVideoCodecIMXBuffer::Release()
+{
+ long count = AtomicDecrement(&m_refs);
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "R- %02d - ref : %d (VPU)\n", m_idx, count);
+#endif
+ if (count == 2)
+ {
+ // Only referenced by the coded and its next frame, release the previous
+ SAFE_RELEASE(m_previousBuffer);
+ }
+ if (count == 1)
+ {
+ // If count drops to 1 then the only reference is being held by the codec
+ // that it can be released in the next Decode call.
+ if(m_frameBuffer != NULL)
+ {
+ m_rendered = true;
+ SAFE_RELEASE(m_previousBuffer);
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "R %02d (VPU)\n", m_idx);
+#endif
+ }
+ }
+ else if (count == 0)
+ {
+ delete this;
+ }
+
+ return count;
+}
+
+bool CDVDVideoCodecIMXBuffer::IsValid()
+{
+ return m_frameBuffer != NULL;
+}
+
+bool CDVDVideoCodecIMXBuffer::Rendered() const
+{
+ return m_rendered;
+}
+
+void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo,
+ CDVDVideoCodecIMXBuffer *previous)
+{
+ // No lock necessary because at this time there is definitely no
+ // thread still holding a reference
+ m_frameBuffer = frameInfo->pDisplayFrameBuf;
+ m_rendered = false;
+ m_previousBuffer = previous;
+ if (m_previousBuffer)
+ m_previousBuffer->Lock();
+
+ iWidth = frameInfo->pExtInfo->nFrmWidth;
+ iHeight = frameInfo->pExtInfo->nFrmHeight;
+ GET_VIRT_ADDR(this) = m_frameBuffer->pbufVirtY;
+ GET_PHYS_ADDR(this) = m_frameBuffer->pbufY;
+ GET_FIELDTYPE(this) = (uint8_t*)frameInfo->eFieldType;
+}
+
+VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle)
+{
+ // Again no lock required because this is only issued after the last
+ // external reference was released
+ VpuDecRetCode ret = VPU_DEC_RET_FAILURE;
+
+ if((m_frameBuffer != NULL) && *handle)
+ {
+ ret = VPU_DecOutFrameDisplayed(*handle, m_frameBuffer);
+ if(ret != VPU_DEC_RET_SUCCESS)
+ CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret);
+ }
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "- %02d (VPU)\n", m_idx);
+#endif
+ m_rendered = false;
+ m_frameBuffer = NULL;
+ m_pts = DVD_NOPTS_VALUE;
+ SAFE_RELEASE(m_previousBuffer);
+
+ return ret;
+}
+
+void CDVDVideoCodecIMXBuffer::SetPts(double pts)
+{
+ m_pts = pts;
+}
+
+double CDVDVideoCodecIMXBuffer::GetPts(void) const
+{
+ return m_pts;
+}
+
+CDVDVideoCodecIMXBuffer *CDVDVideoCodecIMXBuffer::GetPreviousBuffer() const
+{
+ return m_previousBuffer;
+}
+
+CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer()
+{
+ assert(m_refs == 0);
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "~ %02d (VPU)\n", m_idx);
+#endif
+}
+
+#ifdef TRACE_FRAMES
+CDVDVideoCodecIPUBuffer::CDVDVideoCodecIPUBuffer(int idx)
+ : m_refs(1)
+ , m_idx(idx)
+#else
+CDVDVideoCodecIPUBuffer::CDVDVideoCodecIPUBuffer()
+ : m_refs(1)
+#endif
+ , m_source(NULL)
+ , m_pPhyAddr(NULL)
+ , m_pVirtAddr(NULL)
+ , m_nSize(0)
+{
+}
+
+CDVDVideoCodecIPUBuffer::~CDVDVideoCodecIPUBuffer()
+{
+ assert(m_refs == 0);
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "~ %02d (IPU)\n", m_idx);
+#endif
+}
+
+void CDVDVideoCodecIPUBuffer::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 CDVDVideoCodecIPUBuffer::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 CDVDVideoCodecIPUBuffer::IsValid()
+{
+ return m_source && m_source->IsValid() && m_pPhyAddr;
+}
+
+bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecIMXBuffer *buffer,
+ VpuFieldType fieldType, int fieldFmt,
+ bool lowMotion)
+{
+ CDVDVideoCodecIMXBuffer *previousBuffer;
+ struct ipu_task task;
+ memset(&task, 0, sizeof(task));
+ task.priority = IPU_TASK_PRIORITY_HIGH;
+
+ if (lowMotion)
+ previousBuffer = buffer->GetPreviousBuffer();
+ else
+ previousBuffer = NULL;
+
+ SAFE_RELEASE(m_source);
+
+ iWidth = buffer->iWidth;
+ iHeight = buffer->iHeight;
+
+ // Input is the VPU decoded frame
+ task.input.width = iWidth;
+ task.input.height = iHeight;
+ task.input.format = IPU_PIX_FMT_NV12;
+
+ // Output is our IPU buffer
+ task.output.width = iWidth;
+ task.output.height = iHeight;
+ task.output.format = IPU_PIX_FMT_NV12;
+ task.output.paddr = (int)GET_PHYS_ADDR(this);
+
+ // Fill current and next buffer address
+ if (lowMotion && previousBuffer && previousBuffer->IsValid())
+ {
+ task.input.paddr = (int)GET_PHYS_ADDR(previousBuffer);
+ task.input.paddr_n = (int)GET_PHYS_ADDR(buffer);
+ task.input.deinterlace.motion = LOW_MOTION;
+ }
+ else
+ {
+ task.input.paddr = (int)GET_PHYS_ADDR(buffer);
+ 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;
+ }
+
+ buffer->Lock();
+
+ // Remember the source buffer. This is actually not necessary since the output
+ // buffer is the one that is used by the renderer. But keep it bound for now
+ // since this state is used in IsValid which then needs to become a flag in
+ // this class.
+ m_source = buffer;
+ m_source->Lock();
+
+ buffer->Release();
+
+ return true;
+}
+
+void CDVDVideoCodecIPUBuffer::ReleaseFrameBuffer()
+{
+#ifdef TRACE_FRAMES
+ CLog::Log(LOGDEBUG, "- %02d (IPU)\n", m_idx);
+#endif
+ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock);
+ SAFE_RELEASE(m_source);
+}
+
+bool CDVDVideoCodecIPUBuffer::Allocate(int fd, int width, int height, int nAlign)
+{
+ m_iWidth = Align(width,FRAME_ALIGN);
+ m_iHeight = Align(height,(2*FRAME_ALIGN));
+ // NV12 == 12 bpp
+ m_nSize = m_iWidth*m_iHeight*12/8;
+ m_pPhyAddr = m_nSize;
+
+ GET_PHYS_ADDR(this) = GET_VIRT_ADDR(this) = 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)
+ {
+ GET_PHYS_ADDR(this) = (uint8_t*)Align(m_pPhyAddr, nAlign);
+ GET_VIRT_ADDR(this) = (uint8_t*)Align(m_pVirtAddr, nAlign);
+ }
+ else
+ {
+ GET_PHYS_ADDR(this) = (uint8_t*)m_pPhyAddr;
+ GET_VIRT_ADDR(this) = (uint8_t*)m_pVirtAddr;
+ }
+
+ GET_DEINTERLACER(this) = NULL;
+
+ return true;
+}
+
+bool CDVDVideoCodecIPUBuffer::Free(int fd)
+{
+ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock);
+ 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;
+ }
+
+ GET_PHYS_ADDR(this) = GET_VIRT_ADDR(this) = NULL;
+ SAFE_RELEASE(m_source);
+
+ return ret;
+}
+
+CDVDVideoCodecIPUBuffers::CDVDVideoCodecIPUBuffers()
+ : m_ipuHandle(0)
+ , m_bufferNum(0)
+ , m_buffers(NULL)
+ , m_currentFieldFmt(0)
+{
+}
+
+CDVDVideoCodecIPUBuffers::~CDVDVideoCodecIPUBuffers()
+{
+ Close();
+}
+
+bool CDVDVideoCodecIPUBuffers::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 CDVDVideoCodecIPUBuffer*[m_bufferNum];
+ m_currentFieldFmt = 0;
+
+ for (int i=0; i < m_bufferNum; i++)
+ {
+#ifdef TRACE_FRAMES
+ m_buffers[i] = new CDVDVideoCodecIPUBuffer(i);
+#else
+ m_buffers[i] = new CDVDVideoCodecIPUBuffer;
+#endif
+ if (!m_buffers[i]->Allocate(m_ipuHandle, width, height, nAlign))
+ {
+ Close();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CDVDVideoCodecIPUBuffers::Reset()
+{
+ for (int i=0; i < m_bufferNum; i++)
+ m_buffers[i]->ReleaseFrameBuffer();
+ m_currentFieldFmt = 0;
+}
+
+bool CDVDVideoCodecIPUBuffers::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;
+}
+
+CDVDVideoCodecIPUBuffer *
+CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer,
+ VpuFieldType fieldType, bool lowMotion)
+{
+ CDVDVideoCodecIPUBuffer *target = NULL;
+ bool ret = true;
+
+ // TODO: Needs further checks on real streams
+ if (!m_bufferNum /*|| (fieldType == VPU_FIELD_NONE)*/)
+ 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, (CDVDVideoCodecIMXBuffer*)sourceBuffer,
+ fieldType, m_currentFieldFmt/* | IPU_DEINTERLACE_RATE_EN*/,
+ 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");
+ }
+
+ // Toggle frame index bit
+ //m_currentFieldFmt ^= IPU_DEINTERLACE_RATE_FRAME1;
+
+ return target;
+}
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h 1970-01-01 01:00:00.000000000 +0100
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h 2014-04-13 21:18:35.425480131 +0200
@@ -0,0 +1,215 @@
+#pragma once
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <queue>
+#include <imx-mm/vpu/vpu_wrapper.h>
+#include "DVDVideoCodec.h"
+#include "DVDStreamInfo.h"
+#include "DVDVideoCodecInfo.h"
+#include "threads/CriticalSection.h"
+#include "utils/BitstreamConverter.h"
+
+
+//#define IMX_PROFILE
+//#define TRACE_FRAMES
+
+class CDecMemInfo
+{
+public:
+ CDecMemInfo()
+ : nVirtNum(0)
+ , virtMem(NULL)
+ , nPhyNum(0)
+ , phyMem(NULL)
+ {}
+
+ //virtual mem info
+ int nVirtNum;
+ void** virtMem;
+
+ //phy mem info
+ int nPhyNum;
+ VpuMemDesc* phyMem;
+};
+
+class CDVDVideoCodecIPUBuffer;
+
+class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer
+{
+public:
+#ifdef TRACE_FRAMES
+ CDVDVideoCodecIMXBuffer(int idx);
+#else
+ CDVDVideoCodecIMXBuffer();
+#endif
+
+ // reference counting
+ virtual void Lock();
+ virtual long Release();
+ virtual bool IsValid();
+
+ bool Rendered() const;
+ void Queue(VpuDecOutFrameInfo *frameInfo,
+ CDVDVideoCodecIMXBuffer *previous);
+ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle);
+ void SetPts(double pts);
+ double GetPts(void) const;
+ CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const;
+
+private:
+ // private because we are reference counted
+ virtual ~CDVDVideoCodecIMXBuffer();
+
+private:
+#ifdef TRACE_FRAMES
+ int m_idx;
+#endif
+ long m_refs;
+ VpuFrameBuffer *m_frameBuffer;
+ bool m_rendered;
+ double m_pts;
+ CDVDVideoCodecIMXBuffer *m_previousBuffer; // Holds a the reference counted
+ // previous buffer
+};
+
+// Shared buffer that holds an IPU allocated memory block and serves as target
+// for IPU operations such as deinterlacing, rotation or color conversion.
+class CDVDVideoCodecIPUBuffer : public CDVDVideoCodecBuffer
+{
+public:
+#ifdef TRACE_FRAMES
+ CDVDVideoCodecIPUBuffer(int idx);
+#else
+ CDVDVideoCodecIPUBuffer();
+#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_source == NULL; }
+ bool Process(int fd, CDVDVideoCodecIMXBuffer *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 ~CDVDVideoCodecIPUBuffer();
+
+private:
+#ifdef TRACE_FRAMES
+ int m_idx;
+#endif
+ long m_refs;
+ CDVDVideoCodecBuffer *m_source;
+ int m_pPhyAddr;
+ uint8_t *m_pVirtAddr;
+ int m_iWidth;
+ int m_iHeight;
+ int m_nSize;
+};
+
+// 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 CDVDVideoCodecIPUBuffers
+{
+ public:
+ CDVDVideoCodecIPUBuffers();
+ ~CDVDVideoCodecIPUBuffers();
+
+ bool Init(int width, int height, int numBuffers, int nAlign);
+ bool Reset();
+ bool Close();
+
+ CDVDVideoCodecIPUBuffer *Process(CDVDVideoCodecBuffer *sourceBuffer,
+ VpuFieldType fieldType, bool lowMotion);
+
+ private:
+ int m_ipuHandle;
+ int m_bufferNum;
+ CDVDVideoCodecIPUBuffer **m_buffers;
+ int m_currentFieldFmt;
+};
+
+
+class CDVDVideoCodecIMX : public CDVDVideoCodec
+{
+ friend class CDVDVideoCodecIMXBuffer;
+ friend class CDVDVideoCodecIPUBuffer;
+
+public:
+ CDVDVideoCodecIMX();
+ virtual ~CDVDVideoCodecIMX();
+
+ // Methods from CDVDVideoCodec which require overrides
+ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
+ virtual void Dispose(void);
+ virtual int Decode(BYTE *pData, int iSize, double dts, double pts);
+ virtual void Reset(void);
+ virtual bool ClearPicture(DVDVideoPicture *pDvdVideoPicture);
+ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
+ virtual void SetDropState(bool bDrop);
+ virtual const char* GetName(void) { return (const char*)m_pFormatName; }
+ virtual unsigned GetAllowedReferences();
+
+ static void Enter();
+ static void Leave();
+
+protected:
+
+ bool VpuOpen();
+ bool VpuAllocBuffers(VpuMemInfo *);
+ bool VpuFreeBuffers();
+ bool VpuAllocFrameBuffers();
+ int VpuFindBuffer(void *frameAddr);
+
+ static const int m_extraVpuBuffers; // Number of additional buffers for VPU
+ static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop
+ static CCriticalSection m_codecBufferLock;
+
+ 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
+ CDVDVideoCodecIPUBuffers m_deinterlacer;
+ CDVDVideoCodecIMXBuffer **m_outputBuffers;
+ CDVDVideoCodecIMXBuffer *m_lastBuffer;
+ 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;
+ CBitstreamConverter *m_converter;
+ bool m_convert_bitstream;
+ 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
+};
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h 1970-01-01 01:00:00.000000000 +0100
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h 2014-04-13 21:18:35.425480131 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010-2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DVDVIDEOCODECINFO_H
+#define DVDVIDEOCODECINFO_H
+
+class CDVDVideoCodecBuffer
+{
+public:
+ // reference counting
+ virtual void Lock() = 0;
+ virtual long Release() = 0;
+ virtual bool IsValid() = 0;
+
+ uint32_t iWidth;
+ uint32_t iHeight;
+ uint8_t* data[4]; // [4] = alpha channel, currently not used
+ int iLineSize[4]; // [4] = alpha channel, currently not used
+};
+
+#endif // DVDVIDEOCODECINFO_H
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2014-04-13 21:22:38.706937819 +0200
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2014-04-13 21:18:35.427480135 +0200
@@ -24,6 +24,9 @@
SRCS += OpenMaxVideo.cpp
SRCS += DVDVideoCodecOpenMax.cpp
endif
+ifeq (@USE_IMXVPU@,1)
+SRCS += DVDVideoCodecIMX.cpp
+endif
ifeq (@USE_LIBAMCODEC@,1)
SRCS += AMLCodec.cpp
SRCS += DVDVideoCodecAmlogic.cpp
diff -Naur xbmc-13b3/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
--- xbmc-13b3/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2014-04-13 21:22:38.877937332 +0200
+++ xbmc-13b3-imx6/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2014-04-13 21:18:35.456480202 +0200
@@ -995,6 +995,8 @@
case RENDER_FMT_EGLIMG: return "EGLIMG";
case RENDER_FMT_BYPASS: return "BYPASS";
case RENDER_FMT_MEDIACODEC:return "MEDIACODEC";
+ case RENDER_FMT_YV12_BUFFER: return "YV12BUF";
+ case RENDER_FMT_IMXMAP: return "IMXMAP";
case RENDER_FMT_NONE: return "NONE";
}
return "UNKNOWN";
diff -Naur xbmc-13b3/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp xbmc-13b3-imx6/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
--- xbmc-13b3/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp 2014-04-13 21:22:38.630938033 +0200
+++ xbmc-13b3-imx6/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp 2014-04-13 21:18:35.391480053 +0200
@@ -76,6 +76,17 @@
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
#endif
+#ifdef HAS_IMXVPU
+#include "windowing/egl/EGLWrapper.h"
+#include "DVDCodecs/Video/DVDVideoCodecIMX.h"
+
+#define GL_VIV_NV12 0x8FC1
+typedef void (GL_APIENTRYP PFNGLTEXDIRECTVIVMAPPROC) (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical);
+typedef void (GL_APIENTRYP PFNGLTEXDIRECTINVALIDATEVIVPROC) (GLenum Target);
+static PFNGLTEXDIRECTVIVMAPPROC glTexDirectVIVMap;
+static PFNGLTEXDIRECTINVALIDATEVIVPROC glTexDirectInvalidateVIV;
+#endif
+
#if defined(TARGET_ANDROID)
#include "DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h"
#endif
@@ -100,6 +111,7 @@
#if defined(TARGET_ANDROID)
mediacodec = NULL;
#endif
+ codecinfo = NULL;
}
CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER()
@@ -151,6 +163,12 @@
if (!glEGLImageTargetTexture2DOES)
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
#endif
+#ifdef HAS_IMXVPU
+ if (!glTexDirectVIVMap)
+ glTexDirectVIVMap = (PFNGLTEXDIRECTVIVMAPPROC) CEGLWrapper::GetProcAddress("glTexDirectVIVMap");
+ if (!glTexDirectInvalidateVIV)
+ glTexDirectInvalidateVIV = (PFNGLTEXDIRECTINVALIDATEVIVPROC) CEGLWrapper::GetProcAddress("glTexDirectInvalidateVIV");
+#endif
}
CLinuxRendererGLES::~CLinuxRendererGLES()
@@ -279,6 +297,10 @@
{
return source;
}
+ if ( m_renderMethod & RENDER_IMXMAP )
+ {
+ return source;
+ }
#ifdef HAVE_VIDEOTOOLBOXDECODER
if (m_renderMethod & RENDER_CVREF )
@@ -604,6 +626,10 @@
#if defined(TARGET_ANDROID)
m_formats.push_back(RENDER_FMT_MEDIACODEC);
#endif
+ m_formats.push_back(RENDER_FMT_YV12_BUFFER);
+#ifdef HAS_IMXVPU
+ m_formats.push_back(RENDER_FMT_IMXMAP);
+#endif
// setup the background colour
m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff;
@@ -715,6 +741,16 @@
m_renderMethod = RENDER_MEDIACODEC;
break;
}
+ else if (m_format == RENDER_FMT_YV12_BUFFER)
+ {
+ CLog::Log(LOGNOTICE, "GL: Using YV12 Buffer render method");
+ }
+ else if (m_format == RENDER_FMT_IMXMAP)
+ {
+ CLog::Log(LOGNOTICE, "GL: Using IMXMAP render method");
+ m_renderMethod = RENDER_IMXMAP;
+ break;
+ }
else if (m_format == RENDER_FMT_BYPASS)
{
CLog::Log(LOGNOTICE, "GL: Using BYPASS render method");
@@ -807,6 +843,18 @@
m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture;
m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture;
}
+ else if (m_format == RENDER_FMT_YV12_BUFFER)
+ {
+ m_textureUpload = &CLinuxRendererGLES::UploadYV12BufferTexture;
+ m_textureCreate = &CLinuxRendererGLES::CreateYV12Texture;
+ m_textureDelete = &CLinuxRendererGLES::DeleteYV12Texture;
+ }
+ else if (m_format == RENDER_FMT_IMXMAP)
+ {
+ m_textureUpload = &CLinuxRendererGLES::UploadIMXMAPTexture;
+ m_textureCreate = &CLinuxRendererGLES::CreateIMXMAPTexture;
+ m_textureDelete = &CLinuxRendererGLES::DeleteIMXMAPTexture;
+ }
else
{
// default to YV12 texture handlers
@@ -952,6 +1000,10 @@
{
RenderSurfaceTexture(index, m_currentField);
}
+ else if (m_renderMethod & RENDER_IMXMAP)
+ {
+ RenderIMXMAPTexture(index, m_currentField);
+ }
else
{
RenderSoftware(index, m_currentField);
@@ -1156,7 +1208,7 @@
// imgwidth *= planes[0].pixpertex_x;
// imgheight *= planes[0].pixpertex_y;
// }
-//
+//
// glBegin(GL_QUADS);
//
// glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1);
@@ -1578,6 +1630,85 @@
#endif
}
+void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field)
+{
+#if defined(HAS_IMXVPU)
+#ifdef DEBUG_VERBOSE
+ unsigned int time = XbmcThreads::SystemClockMillis();
+#endif
+
+ YUVPLANE &plane = m_buffers[index].fields[field][0];
+ CDVDVideoCodecBuffer* codecinfo = m_buffers[index].codecinfo;
+
+ if(codecinfo == NULL) return;
+
+ CDVDVideoCodecIMX::Enter();
+
+ if(!codecinfo->IsValid())
+ {
+ CDVDVideoCodecIMX::Leave();
+ return;
+ }
+
+ glDisable(GL_DEPTH_TEST);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(m_textureTarget, plane.id);
+
+ g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
+
+ GLubyte idx[4] = {0, 1, 3, 2}; //determines order of triangle strip
+ GLfloat ver[4][4];
+ GLfloat tex[4][2];
+ GLfloat col[3] = {1.0f, 1.0f, 1.0f};
+
+ GLint posLoc = g_Windowing.GUIShaderGetPos();
+ GLint texLoc = g_Windowing.GUIShaderGetCoord0();
+ GLint colLoc = g_Windowing.GUIShaderGetCol();
+
+ glVertexAttribPointer(posLoc, 4, GL_FLOAT, 0, 0, ver);
+ glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, tex);
+ glVertexAttribPointer(colLoc, 3, GL_FLOAT, 0, 0, col);
+
+ glEnableVertexAttribArray(posLoc);
+ glEnableVertexAttribArray(texLoc);
+ glEnableVertexAttribArray(colLoc);
+
+ // Set vertex coordinates
+ for(int i = 0; i < 4; i++)
+ {
+ ver[i][0] = m_rotatedDestCoords[i].x;
+ ver[i][1] = m_rotatedDestCoords[i].y;
+ ver[i][2] = 0.0f;// set z to 0
+ ver[i][3] = 1.0f;
+ }
+
+ // Set texture coordinates
+ tex[0][0] = tex[3][0] = plane.rect.x1;
+ tex[0][1] = tex[1][1] = plane.rect.y1;
+ tex[1][0] = tex[2][0] = plane.rect.x2;
+ tex[2][1] = tex[3][1] = plane.rect.y2;
+
+ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, idx);
+
+ glDisableVertexAttribArray(posLoc);
+ glDisableVertexAttribArray(texLoc);
+ glDisableVertexAttribArray(colLoc);
+
+ g_Windowing.DisableGUIShader();
+ VerifyGLState();
+
+ glBindTexture(m_textureTarget, 0);
+ VerifyGLState();
+
+ CDVDVideoCodecIMX::Leave();
+
+#ifdef DEBUG_VERBOSE
+ CLog::Log(LOGDEBUG, "RenderIMXMAPTexture %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time);
+#endif
+#endif
+}
+
bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
{
if (!m_bValidated)
@@ -2299,7 +2430,7 @@
glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // This is necessary for non-power-of-two textures
+ // This is necessary for non-power-of-two textures
glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
@@ -2405,7 +2536,7 @@
glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // This is necessary for non-power-of-two textures
+ // This is necessary for non-power-of-two textures
glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
@@ -2479,6 +2610,84 @@
return true;
}
+//********************************************************************************************************
+// Buffer creation, deletion, copying + clearing
+//********************************************************************************************************
+void CLinuxRendererGLES::UploadYV12BufferTexture(int index)
+{
+ YUVBUFFER& buf = m_buffers[index];
+ YV12Image* im = &buf.image;
+ YUVFIELDS& fields = buf.fields;
+
+ if (!buf.codecinfo || !(im->flags & IMAGE_FLAG_READY))
+ return;
+
+ bool deinterlacing;
+ if (m_currentField == FIELD_FULL)
+ deinterlacing = false;
+ else
+ deinterlacing = true;
+
+ glEnable(m_textureTarget);
+ VerifyGLState();
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+
+ if (deinterlacing)
+ {
+ // Load Even Y Field
+ LoadPlane( fields[FIELD_TOP][0] , GL_LUMINANCE, buf.flipindex
+ , im->width, im->height >> 1
+ , buf.codecinfo->iLineSize[0]*2, im->bpp, buf.codecinfo->data[0] );
+
+ // Load Odd Y fields
+ LoadPlane( fields[FIELD_BOT][0], GL_LUMINANCE, buf.flipindex
+ , im->width, im->height >> 1
+ , buf.codecinfo->iLineSize[0]*2, im->bpp, buf.codecinfo->data[0] + buf.codecinfo->iLineSize[0]) ;
+
+ // Load Even U & V Fields
+ LoadPlane( fields[FIELD_TOP][1], GL_LUMINANCE, buf.flipindex
+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
+ , buf.codecinfo->iLineSize[1]*2, im->bpp, buf.codecinfo->data[1] );
+
+ LoadPlane( fields[FIELD_TOP][2], GL_ALPHA, buf.flipindex
+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
+ , buf.codecinfo->iLineSize[2]*2, im->bpp, buf.codecinfo->data[2] );
+
+ // Load Odd U & V Fields
+ LoadPlane( fields[FIELD_BOT][1], GL_LUMINANCE, buf.flipindex
+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
+ , buf.codecinfo->iLineSize[1]*2, im->bpp, buf.codecinfo->data[1] + buf.codecinfo->iLineSize[1] );
+
+ LoadPlane( fields[FIELD_BOT][2], GL_ALPHA, buf.flipindex
+ , im->width >> im->cshift_x, im->height >> (im->cshift_y + 1)
+ , buf.codecinfo->iLineSize[2]*2, im->bpp, buf.codecinfo->data[2] + buf.codecinfo->iLineSize[2] );
+ }
+ else
+ {
+ // Load Y plane
+ LoadPlane( fields[FIELD_FULL][0], GL_LUMINANCE, buf.flipindex
+ , im->width, im->height
+ , buf.codecinfo->iLineSize[0], im->bpp, buf.codecinfo->data[0] );
+
+ //load U plane
+ LoadPlane( fields[FIELD_FULL][1], GL_LUMINANCE, buf.flipindex
+ , im->width >> im->cshift_x, im->height >> im->cshift_y
+ , buf.codecinfo->iLineSize[1], im->bpp, buf.codecinfo->data[1] );
+
+ //load V plane
+ LoadPlane( fields[FIELD_FULL][2], GL_ALPHA, buf.flipindex
+ , im->width >> im->cshift_x, im->height >> im->cshift_y
+ , buf.codecinfo->iLineSize[2], im->bpp, buf.codecinfo->data[2] );
+ }
+
+ VerifyGLState();
+
+ CalculateTextureSourceRects(index, 3);
+
+ glDisable(m_textureTarget);
+}
+
void CLinuxRendererGLES::SetTextureFilter(GLenum method)
{
for (int i = 0 ; i<m_NumYV12Buffers ; i++)
@@ -2508,6 +2717,114 @@
}
}
+//********************************************************************************************************
+// IMXMAP creation, deletion, copying + clearing
+//********************************************************************************************************
+void CLinuxRendererGLES::UploadIMXMAPTexture(int index)
+{
+#ifdef HAS_IMXVPU
+ YUVBUFFER& buf = m_buffers[index];
+ CDVDVideoCodecBuffer* codecinfo = buf.codecinfo;
+
+ if(codecinfo)
+ {
+ CDVDVideoCodecIMX::Enter();
+
+ if(!codecinfo->IsValid())
+ {
+ CDVDVideoCodecIMX::Leave();
+ return;
+ }
+
+ YUVPLANE &plane = m_buffers[index].fields[0][0];
+ CDVDVideoCodecIPUBuffers *deinterlacer = (CDVDVideoCodecIPUBuffers*)codecinfo->data[2];
+
+ if (deinterlacer)
+ {
+ EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
+
+ if (deinterlacemode != VS_DEINTERLACEMODE_OFF)
+ {
+ CDVDVideoCodecBuffer *deint;
+ EINTERLACEMETHOD interlacemethod = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod;
+ deint = deinterlacer->Process(codecinfo, (VpuFieldType)(int)codecinfo->data[3],
+ interlacemethod == VS_INTERLACEMETHOD_DEINTERLACE);
+ if (deint)
+ {
+ SAFE_RELEASE(buf.codecinfo);
+ buf.codecinfo = deint;
+ buf.codecinfo->Lock();
+ codecinfo = buf.codecinfo;
+ }
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(m_textureTarget, plane.id);
+
+ GLuint physical = ~0U;
+ GLvoid *virt = (GLvoid*)codecinfo->data[0];
+ glTexDirectVIVMap(m_textureTarget, codecinfo->iWidth, codecinfo->iHeight, GL_VIV_NV12,
+ (GLvoid **)&virt, &physical);
+ glTexDirectInvalidateVIV(m_textureTarget);
+
+ glBindTexture(m_textureTarget, 0);
+
+ plane.flipindex = m_buffers[index].flipindex;
+ plane.texwidth = codecinfo->iWidth;
+ plane.texheight = codecinfo->iHeight;
+
+ CalculateTextureSourceRects(index, 1);
+
+ CDVDVideoCodecIMX::Leave();
+ }
+
+#endif
+}
+void CLinuxRendererGLES::DeleteIMXMAPTexture(int index)
+{
+ YUVBUFFER &buf = m_buffers[index];
+ YUVPLANE &plane = buf.fields[0][0];
+
+ if(plane.id && glIsTexture(plane.id))
+ glDeleteTextures(1, &plane.id);
+ plane.id = 0;
+
+ SAFE_RELEASE(buf.codecinfo);
+}
+bool CLinuxRendererGLES::CreateIMXMAPTexture(int index)
+{
+ YV12Image &im = m_buffers[index].image;
+ YUVFIELDS &fields = m_buffers[index].fields;
+ YUVPLANE &plane = fields[0][0];
+
+ DeleteEGLIMGTexture(index);
+
+ memset(&im , 0, sizeof(im));
+ memset(&fields, 0, sizeof(fields));
+
+ im.height = m_sourceHeight;
+ im.width = m_sourceWidth;
+
+ plane.texwidth = 0; // Must be actual frame width for pseudo-cropping
+ plane.texheight = 0; // Must be actual frame height for pseudo-cropping
+ plane.pixpertex_x = 1;
+ plane.pixpertex_y = 1;
+
+ glEnable(m_textureTarget);
+ glGenTextures(1, &plane.id);
+ VerifyGLState();
+
+ glBindTexture(m_textureTarget, plane.id);
+
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glDisable(m_textureTarget);
+ return true;
+}
+
+
bool CLinuxRendererGLES::Supports(ERENDERFEATURE feature)
{
// Player controls render, let it dictate available render features
@@ -2574,9 +2891,14 @@
if(m_renderMethod & RENDER_CVREF)
return false;
+#ifdef HAS_IMXVPU
+ if(mode == VS_DEINTERLACEMODE_AUTO)
+ return true;
+#else
if(mode == VS_DEINTERLACEMODE_AUTO
|| mode == VS_DEINTERLACEMODE_FORCE)
return true;
+#endif
return false;
}
@@ -2605,6 +2927,15 @@
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
@@ -2653,6 +2984,9 @@
if(m_renderMethod & RENDER_CVREF)
return VS_INTERLACEMETHOD_NONE;
+ if(m_renderMethod & RENDER_IMXMAP)
+ return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
+
#if defined(__i386__) || defined(__x86_64__)
return VS_INTERLACEMETHOD_DEINTERLACE_HALF;
#else
@@ -2737,5 +3071,16 @@
}
#endif
+void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecBuffer *codecinfo, int index)
+{
+ YUVBUFFER &buf = m_buffers[index];
+
+ SAFE_RELEASE(buf.codecinfo);
+ buf.codecinfo = codecinfo;
+
+ if (codecinfo)
+ codecinfo->Lock();
+}
+
#endif
diff -Naur xbmc-13b3/xbmc/cores/VideoRenderers/LinuxRendererGLES.h xbmc-13b3-imx6/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
--- xbmc-13b3/xbmc/cores/VideoRenderers/LinuxRendererGLES.h 2014-04-13 21:22:38.615938076 +0200
+++ xbmc-13b3-imx6/xbmc/cores/VideoRenderers/LinuxRendererGLES.h 2014-04-13 21:18:35.391480053 +0200
@@ -33,6 +33,7 @@
#include "guilib/GraphicContext.h"
#include "BaseRenderer.h"
#include "xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h"
+#include "xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h"
class CRenderCapture;
@@ -89,7 +90,8 @@
RENDER_CVREF = 0x080,
RENDER_BYPASS = 0x100,
RENDER_EGLIMG = 0x200,
- RENDER_MEDIACODEC = 0x400
+ RENDER_MEDIACODEC = 0x400,
+ RENDER_IMXMAP = 0x800
};
enum RenderQuality
@@ -173,6 +175,7 @@
// mediaCodec
virtual void AddProcessor(CDVDMediaCodecInfo *mediacodec, int index);
#endif
+ virtual void AddProcessor(CDVDVideoCodecBuffer *codecinfo, int index);
protected:
virtual void Render(DWORD flags, int index);
@@ -212,6 +215,12 @@
void DeleteSurfaceTexture(int index);
bool CreateSurfaceTexture(int index);
+ void UploadYV12BufferTexture(int index);
+
+ void UploadIMXMAPTexture(int index);
+ void DeleteIMXMAPTexture(int index);
+ bool CreateIMXMAPTexture(int index);
+
void CalculateTextureSourceRects(int source, int num_planes);
// renderers
@@ -222,6 +231,7 @@
void RenderEglImage(int index, int field); // Android OES texture
void RenderCoreVideoRef(int index, int field); // CoreVideo reference
void RenderSurfaceTexture(int index, int field);// MediaCodec rendering using SurfaceTexture
+ void RenderIMXMAPTexture(int index, int field); // IMXMAP rendering
CFrameBufferObject m_fbo;
@@ -288,6 +298,7 @@
// mediacodec
CDVDMediaCodecInfo *mediacodec;
#endif
+ CDVDVideoCodecBuffer *codecinfo;
};
typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS];
diff -Naur xbmc-13b3/xbmc/cores/VideoRenderers/RenderFormats.h xbmc-13b3-imx6/xbmc/cores/VideoRenderers/RenderFormats.h
--- xbmc-13b3/xbmc/cores/VideoRenderers/RenderFormats.h 2014-04-13 21:22:38.629938036 +0200
+++ xbmc-13b3-imx6/xbmc/cores/VideoRenderers/RenderFormats.h 2014-04-13 21:18:35.394480060 +0200
@@ -37,6 +37,8 @@
RENDER_FMT_BYPASS,
RENDER_FMT_EGLIMG,
RENDER_FMT_MEDIACODEC,
+ RENDER_FMT_YV12_BUFFER,
+ RENDER_FMT_IMXMAP,
};
#endif
diff -Naur xbmc-13b3/xbmc/cores/VideoRenderers/RenderManager.cpp xbmc-13b3-imx6/xbmc/cores/VideoRenderers/RenderManager.cpp
--- xbmc-13b3/xbmc/cores/VideoRenderers/RenderManager.cpp 2014-04-13 21:22:38.619938064 +0200
+++ xbmc-13b3-imx6/xbmc/cores/VideoRenderers/RenderManager.cpp 2014-04-13 21:18:35.394480060 +0200
@@ -928,6 +928,10 @@
else if(pic.format == RENDER_FMT_MEDIACODEC)
m_pRenderer->AddProcessor(pic.mediacodec, index);
#endif
+#ifdef HAS_IMXVPU
+ else if(pic.format == RENDER_FMT_YV12_BUFFER || pic.format == RENDER_FMT_IMXMAP)
+ m_pRenderer->AddProcessor(pic.codecinfo, index);
+#endif
m_pRenderer->ReleaseImage(index, false);
diff -Naur xbmc-13b3/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp xbmc-13b3-imx6/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp
--- xbmc-13b3/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2014-04-13 21:22:38.593938138 +0200
+++ xbmc-13b3-imx6/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2014-04-13 21:18:35.395480062 +0200
@@ -39,12 +39,12 @@
//
// Transformation matrixes for different colorspaces.
//
-static float yuv_coef_bt601[4][4] =
+static float yuv_coef_bt601[4][4] =
{
{ 1.0f, 1.0f, 1.0f, 0.0f },
{ 0.0f, -0.344f, 1.773f, 0.0f },
{ 1.403f, -0.714f, 0.0f, 0.0f },
- { 0.0f, 0.0f, 0.0f, 0.0f }
+ { 0.0f, 0.0f, 0.0f, 0.0f }
};
static float yuv_coef_bt709[4][4] =
@@ -55,7 +55,7 @@
{ 0.0f, 0.0f, 0.0f, 0.0f }
};
-static float yuv_coef_ebu[4][4] =
+static float yuv_coef_ebu[4][4] =
{
{ 1.0f, 1.0f, 1.0f, 0.0f },
{ 0.0f, -0.3960f, 2.029f, 0.0f },
@@ -74,19 +74,19 @@
static float** PickYUVConversionMatrix(unsigned flags)
{
// Pick the matrix.
-
+
switch(CONF_FLAGS_YUVCOEF_MASK(flags))
{
case CONF_FLAGS_YUVCOEF_240M:
return (float**)yuv_coef_smtp240m; break;
case CONF_FLAGS_YUVCOEF_BT709:
return (float**)yuv_coef_bt709; break;
- case CONF_FLAGS_YUVCOEF_BT601:
+ case CONF_FLAGS_YUVCOEF_BT601:
return (float**)yuv_coef_bt601; break;
case CONF_FLAGS_YUVCOEF_EBU:
return (float**)yuv_coef_ebu; break;
}
-
+
return (float**)yuv_coef_bt601;
}
@@ -228,7 +228,7 @@
m_hProj = -1;
m_hModel = -1;
m_hAlpha = -1;
- if (m_format == RENDER_FMT_YUV420P)
+ if (m_format == RENDER_FMT_YUV420P || m_format == RENDER_FMT_YV12_BUFFER)
m_defines += "#define XBMC_YV12\n";
else if (m_format == RENDER_FMT_NV12)
m_defines += "#define XBMC_NV12\n";
diff -Naur xbmc-13b3/xbmc/input/linux/LinuxInputDevices.cpp xbmc-13b3-imx6/xbmc/input/linux/LinuxInputDevices.cpp
diff -Naur xbmc-13b3/xbmc/powermanagement/PowerManager.cpp xbmc-13b3-imx6/xbmc/powermanagement/PowerManager.cpp
diff -Naur xbmc-13b3/xbmc/windowing/egl/EGLNativeTypeIMX.cpp xbmc-13b3-imx6/xbmc/windowing/egl/EGLNativeTypeIMX.cpp
--- xbmc-13b3/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 1970-01-01 01:00:00.000000000 +0100
+++ xbmc-13b3-imx6/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 2014-04-13 21:18:35.990481429 +0200
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2011-2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/mxcfb.h>
+#include "system.h"
+#include <EGL/egl.h>
+
+#include "EGLNativeTypeIMX.h"
+#include <math.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "utils/log.h"
+#include "utils/RegExp.h"
+#include "utils/StringUtils.h"
+#include "utils/Environment.h"
+#include "guilib/gui3d.h"
+#include "windowing/WindowingFactory.h"
+#include "cores/AudioEngine/AEFactory.h"
+#include <fstream>
+
+CEGLNativeTypeIMX::CEGLNativeTypeIMX()
+ : m_display(NULL)
+ , m_window(NULL)
+{
+}
+
+CEGLNativeTypeIMX::~CEGLNativeTypeIMX()
+{
+}
+
+bool CEGLNativeTypeIMX::CheckCompatibility()
+{
+ std::ifstream file("/sys/class/graphics/fb0/fsl_disp_dev_property");
+ return file;
+}
+
+void CEGLNativeTypeIMX::Initialize()
+{
+ int fd;
+
+ fd = open("/dev/fb0",O_RDWR);
+ if (fd < 0)
+ {
+ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__);
+ return;
+ }
+
+ // Unblank the fb
+ if (ioctl(fd, FBIOBLANK, 0) < 0)
+ {
+ CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__);
+ }
+
+ close(fd);
+
+ // Check if we can change the framebuffer resolution
+ fd = open("/sys/class/graphics/fb0/mode", O_RDWR);
+ if (fd >= 0)
+ {
+ CLog::Log(LOGNOTICE, "%s - graphics sysfs is writable", __FUNCTION__);
+ m_readonly = false;
+ }
+ else
+ {
+ CLog::Log(LOGNOTICE, "%s - graphics sysfs is read-only", __FUNCTION__);
+ m_readonly = true;
+ }
+ close(fd);
+
+ return;
+}
+
+void CEGLNativeTypeIMX::Destroy()
+{
+ struct fb_fix_screeninfo fixed_info;
+ void *fb_buffer;
+ int fd;
+
+ fd = open("/dev/fb0",O_RDWR);
+ if (fd < 0)
+ {
+ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__);
+ return;
+ }
+
+ ioctl( fd, FBIOGET_FSCREENINFO, &fixed_info);
+ // Black fb0
+ fb_buffer = mmap(NULL, fixed_info.smem_len, PROT_WRITE, MAP_SHARED, fd, 0);
+ if (fb_buffer == MAP_FAILED)
+ {
+ CLog::Log(LOGERROR, "%s - fb mmap failed %s.\n", __FUNCTION__, strerror(errno));
+ }
+ else
+ {
+ memset(fb_buffer, 0x0, fixed_info.smem_len);
+ munmap(fb_buffer, fixed_info.smem_len);
+ }
+
+ close(fd);
+
+ return;
+}
+
+bool CEGLNativeTypeIMX::CreateNativeDisplay()
+{
+ // Force double-buffering
+ CEnvironment::setenv("FB_MULTI_BUFFER", "2", 0);
+
+ // EGL will be rendered on fb0
+ m_display = fbGetDisplayByIndex(0);
+ m_nativeDisplay = &m_display;
+ return true;
+}
+
+bool CEGLNativeTypeIMX::CreateNativeWindow()
+{
+ m_window = fbCreateWindow(m_display, 0, 0, 0, 0);
+ m_nativeWindow = &m_window;
+ return true;
+}
+
+bool CEGLNativeTypeIMX::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const
+{
+ if (!nativeDisplay)
+ return false;
+ if (!m_nativeDisplay)
+ return false;
+ *nativeDisplay = (XBNativeDisplayType*)m_nativeDisplay;
+ return true;
+}
+
+bool CEGLNativeTypeIMX::GetNativeWindow(XBNativeWindowType **nativeWindow) const
+{
+ if (!nativeWindow)
+ return false;
+ if (!m_nativeWindow || !m_window)
+ return false;
+ *nativeWindow = (XBNativeWindowType*)m_nativeWindow;
+ return true;
+}
+
+bool CEGLNativeTypeIMX::DestroyNativeDisplay()
+{
+ if (m_display)
+ fbDestroyDisplay(m_display);
+ m_display = NULL;
+ return true;
+}
+
+bool CEGLNativeTypeIMX::DestroyNativeWindow()
+{
+ if (m_window)
+ fbDestroyWindow(m_window);
+ m_window = NULL;
+ return true;
+}
+
+bool CEGLNativeTypeIMX::GetNativeResolution(RESOLUTION_INFO *res) const
+{
+ std::string mode;
+ get_sysfs_str("/sys/class/graphics/fb0/mode", mode);
+ return ModeToResolution(mode, res);
+}
+
+bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res)
+{
+ if (m_readonly)
+ return false;
+
+ std::string mode;
+ get_sysfs_str("/sys/class/graphics/fb0/mode", mode);
+ if (res.strId == mode)
+ return false;
+
+ DestroyNativeWindow();
+ DestroyNativeDisplay();
+
+ set_sysfs_str("/sys/class/graphics/fb0/mode", res.strId);
+
+ CreateNativeDisplay();
+
+ CLog::Log(LOGDEBUG, "%s: %s",__FUNCTION__, res.strId.c_str());
+
+ // Reset AE
+ CAEFactory::DeviceChange();
+
+ return true;
+}
+
+bool CEGLNativeTypeIMX::ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions)
+{
+ if (m_readonly)
+ return false;
+
+ std::string valstr;
+ get_sysfs_str("/sys/class/graphics/fb0/modes", valstr);
+ std::vector<CStdString> probe_str;
+ StringUtils::SplitString(valstr, "\n", probe_str);
+
+ resolutions.clear();
+ RESOLUTION_INFO res;
+ for (size_t i = 0; i < probe_str.size(); i++)
+ {
+ if(!StringUtils::StartsWith(probe_str[i], "S:"))
+ continue;
+ if(ModeToResolution(probe_str[i], &res))
+ resolutions.push_back(res);
+ }
+ return resolutions.size() > 0;
+}
+
+bool CEGLNativeTypeIMX::GetPreferredResolution(RESOLUTION_INFO *res) const
+{
+ return GetNativeResolution(res);
+}
+
+bool CEGLNativeTypeIMX::ShowWindow(bool show)
+{
+ // Force vsync by default
+ eglSwapInterval(g_Windowing.GetEGLDisplay(), 1);
+ EGLint result = eglGetError();
+ if(result != EGL_SUCCESS)
+ CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, result);
+
+ return false;
+}
+
+int CEGLNativeTypeIMX::get_sysfs_str(std::string path, std::string& valstr) const
+{
+ int len;
+ char buf[256] = {0};
+
+ int fd = open(path.c_str(), O_RDONLY);
+ if (fd >= 0)
+ {
+ while ((len = read(fd, buf, 255)) > 0)
+ valstr.append(buf, len);
+ close(fd);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "%s: error reading %s",__FUNCTION__, path.c_str());
+ valstr = "fail";
+ return -1;
+ }
+ return 0;
+}
+
+int CEGLNativeTypeIMX::set_sysfs_str(std::string path, std::string val) const
+{
+ int fd = open(path.c_str(), O_WRONLY);
+ if (fd >= 0)
+ {
+ val += '\n';
+ write(fd, val.c_str(), val.size());
+ close(fd);
+ return 0;
+ }
+ CLog::Log(LOGERROR, "%s: error writing %s",__FUNCTION__, path.c_str());
+ return -1;
+}
+
+bool CEGLNativeTypeIMX::ModeToResolution(std::string mode, RESOLUTION_INFO *res) const
+{
+ if (!res)
+ return false;
+
+ res->iWidth = 0;
+ res->iHeight= 0;
+
+ if(mode.empty())
+ return false;
+
+ std::string fromMode = StringUtils::Mid(mode, 2);
+ StringUtils::Trim(fromMode);
+
+ CRegExp split(true);
+ split.RegComp("([0-9]+)x([0-9]+)([pi])-([0-9]+)");
+ if (split.RegFind(fromMode) < 0)
+ return false;
+
+ int w = atoi(split.GetMatch(1).c_str());
+ int h = atoi(split.GetMatch(2).c_str());
+ std::string p = split.GetMatch(3);
+ int r = atoi(split.GetMatch(4).c_str());
+
+ res->iWidth = w;
+ res->iHeight= h;
+ res->iScreenWidth = w;
+ res->iScreenHeight= h;
+ res->fRefreshRate = r;
+ res->dwFlags = p[0] == 'p' ? D3DPRESENTFLAG_PROGRESSIVE : D3DPRESENTFLAG_INTERLACED;
+
+ res->iScreen = 0;
+ res->bFullScreen = true;
+ res->iSubtitles = (int)(0.965 * res->iHeight);
+ res->fPixelRatio = 1.0f;
+ res->strMode = StringUtils::Format("%dx%d @ %.2f%s - Full Screen", res->iScreenWidth, res->iScreenHeight, res->fRefreshRate,
+ res->dwFlags & D3DPRESENTFLAG_INTERLACED ? "i" : "");
+ res->strId = mode;
+
+ return res->iWidth > 0 && res->iHeight> 0;
+}
+
diff -Naur xbmc-13b3/xbmc/windowing/egl/EGLNativeTypeIMX.h xbmc-13b3-imx6/xbmc/windowing/egl/EGLNativeTypeIMX.h
--- xbmc-13b3/xbmc/windowing/egl/EGLNativeTypeIMX.h 1970-01-01 01:00:00.000000000 +0100
+++ xbmc-13b3-imx6/xbmc/windowing/egl/EGLNativeTypeIMX.h 2014-04-13 21:18:35.990481429 +0200
@@ -0,0 +1,60 @@
+#pragma once
+
+/*
+ * Copyright (C) 2011-2013 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/fb.h>
+#include "EGLNativeType.h"
+#include "EGL/eglvivante.h"
+
+class CEGLNativeTypeIMX : public CEGLNativeType
+{
+public:
+ CEGLNativeTypeIMX();
+ virtual ~CEGLNativeTypeIMX();
+ virtual std::string GetNativeName() const { return "iMX"; }
+ virtual bool CheckCompatibility();
+ virtual void Initialize();
+ virtual void Destroy();
+ virtual int GetQuirks() { return EGL_QUIRK_NONE; }
+
+ virtual bool CreateNativeDisplay();
+ virtual bool CreateNativeWindow();
+ virtual bool GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const;
+ virtual bool GetNativeWindow(XBNativeWindowType **nativeWindow) const;
+
+ virtual bool DestroyNativeWindow();
+ virtual bool DestroyNativeDisplay();
+
+ virtual bool GetNativeResolution(RESOLUTION_INFO *res) const;
+ virtual bool SetNativeResolution(const RESOLUTION_INFO &res);
+ virtual bool ProbeResolutions(std::vector<RESOLUTION_INFO> &resolutions);
+ virtual bool GetPreferredResolution(RESOLUTION_INFO *res) const;
+
+ virtual bool ShowWindow(bool show);
+
+protected:
+ bool m_readonly;
+ int get_sysfs_str(std::string path, std::string& valstr) const;
+ int set_sysfs_str(std::string path, std::string val) const;
+ bool ModeToResolution(std::string mode, RESOLUTION_INFO *res) const;
+
+ EGLNativeDisplayType m_display;
+ EGLNativeWindowType m_window;
+};
diff -Naur xbmc-13b3/xbmc/windowing/egl/EGLWrapper.cpp xbmc-13b3-imx6/xbmc/windowing/egl/EGLWrapper.cpp
--- xbmc-13b3/xbmc/windowing/egl/EGLWrapper.cpp 2014-04-13 21:22:38.089939567 +0200
+++ xbmc-13b3-imx6/xbmc/windowing/egl/EGLWrapper.cpp 2014-04-13 21:18:35.990481429 +0200
@@ -17,16 +17,17 @@
* <http://www.gnu.org/licenses/>.
*
*/
-
#include "system.h"
#ifdef HAS_EGL
-
#include "utils/log.h"
#include "EGLNativeTypeAndroid.h"
#include "EGLNativeTypeAmlogic.h"
#include "EGLNativeTypeRaspberryPI.h"
#include "EGLNativeTypeWayland.h"
+#ifdef HAS_IMXVPU
+#include "EGLNativeTypeIMX.h"
+#endif
#include "EGLWrapper.h"
#define CheckError() m_result = eglGetError(); if(m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
@@ -83,7 +84,11 @@
if ((nativeGuess = CreateEGLNativeType<CEGLNativeTypeWayland>(implementation)) ||
(nativeGuess = CreateEGLNativeType<CEGLNativeTypeAndroid>(implementation)) ||
(nativeGuess = CreateEGLNativeType<CEGLNativeTypeAmlogic>(implementation)) ||
- (nativeGuess = CreateEGLNativeType<CEGLNativeTypeRaspberryPI>(implementation)))
+ (nativeGuess = CreateEGLNativeType<CEGLNativeTypeRaspberryPI>(implementation))
+#ifdef HAS_IMXFB
+ || (nativeGuess = CreateEGLNativeType<CEGLNativeTypeIMX>(implementation))
+#endif
+ )
{
m_nativeTypes = nativeGuess;
diff -Naur xbmc-13b3/xbmc/windowing/egl/Makefile.in xbmc-13b3-imx6/xbmc/windowing/egl/Makefile.in
--- xbmc-13b3/xbmc/windowing/egl/Makefile.in 2014-04-13 21:22:38.063939640 +0200
+++ xbmc-13b3-imx6/xbmc/windowing/egl/Makefile.in 2014-04-13 21:18:35.990481429 +0200
@@ -24,6 +24,10 @@
wayland/XBMCSurface.cpp
endif
+ifeq (@USE_IMXFB@,1)
+SRCS+= EGLNativeTypeIMX.cpp
+endif
+
LIB = windowing_egl.a
include ../../../Makefile.include