mirror of
https://github.com/LibreELEC/LibreELEC.tv
synced 2025-09-24 19:46:01 +07:00
3049 lines
92 KiB
Diff
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, ¶m);
|
|
+ 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, ¶m);
|
|
+ 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
|