diff --git a/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support-master-pr.patch b/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support-master-pr.patch new file mode 100644 index 0000000000..e173824344 --- /dev/null +++ b/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support-master-pr.patch @@ -0,0 +1,14028 @@ +From 058c482cfe48dfc9e27bebd812777baf03b2ef0f Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Fri, 31 Jan 2014 14:43:24 +0100 +Subject: [PATCH 01/56] ADD: Freeescale imx h/w codec + +--- + configure.in | 13 +- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 23 +- + xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 2 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 103 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 7 + + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 4 + + xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 18 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 7 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1737 ++++++++++++++++++++ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 191 +++ + xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 3 + + xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c | 752 +++++++++ + xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h | 170 ++ + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + + xbmc/input/linux/LinuxInputDevices.cpp | 3 +- + xbmc/powermanagement/PowerManager.cpp | 8 +- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 272 +++ + xbmc/windowing/egl/EGLNativeTypeIMX.h | 62 + + xbmc/windowing/egl/EGLWrapper.cpp | 6 +- + xbmc/windowing/egl/Makefile.in | 1 + + 21 files changed, 3363 insertions(+), 21 deletions(-) + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h + create mode 100644 xbmc/windowing/egl/EGLNativeTypeIMX.cpp + create mode 100644 xbmc/windowing/egl/EGLNativeTypeIMX.h + +diff --git a/configure.in b/configure.in +index 20caba5..abc9d01 100644 +--- a/configure.in ++++ b/configure.in +@@ -537,7 +537,7 @@ AC_ARG_ENABLE([gtest], + + 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]) + +@@ -2004,6 +2004,17 @@ for codecs in `echo $add_codecs | sed 's/,/ /g'`; do + *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 --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index b48a4fc..8c0bad6 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -720,7 +720,10 @@ void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) + * 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 @@ void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) + * 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 @@ void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) + + 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 --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +index 711ec04..d113f09 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +@@ -841,7 +841,7 @@ unsigned int CAEConvert::Float_S24NE4(float *data, const unsigned int samples, u + _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 --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 72eb725..913fb0f 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -20,6 +20,10 @@ + + //#define DEBUG_VERBOSE 1 + ++#ifdef HAS_IMXVPU ++#include ++#endif ++ + #include "system.h" + #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS) + #include "config.h" +@@ -66,6 +70,11 @@ extern "C" { + #ifdef TARGET_DARWIN_IOS + #include "osx/DarwinUtils.h" + #endif ++ ++#ifdef HAS_IMXVPU ++#include "DVDCodecs/Video/DVDVideoCodecIMX.h" ++#endif ++ + #if defined(HAS_LIBSTAGEFRIGHT) + #include + #include +@@ -103,6 +112,10 @@ CLinuxRendererGLES::YUVBUFFER::YUVBUFFER() + #if defined(TARGET_ANDROID) + mediacodec = NULL; + #endif ++#ifdef HAS_IMXVPU ++ imxOutputFrame = NULL; ++#endif ++ + } + + CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER() +@@ -113,6 +126,23 @@ CLinuxRendererGLES::CLinuxRendererGLES() + { + m_textureTarget = GL_TEXTURE_2D; + ++ /* FIXME a verifier */ ++#if 0 ++ ++ for (int i = 0; i < NUM_BUFFERS; i++) ++ { ++#if defined(HAVE_LIBOPENMAX) ++ m_buffers[i].openMaxBuffer = 0; ++#endif ++#ifdef HAVE_VIDEOTOOLBOXDECODER ++ m_buffers[i].cvBufferRef = NULL; ++#endif ++#ifdef HAS_IMXVPU ++ m_buffers[i].imx = NULL; ++#endif ++ } ++#endif ++ + m_renderMethod = RENDER_GLSL; + m_oldRenderMethod = m_renderMethod; + m_renderQuality = RQ_SINGLEPASS; +@@ -498,18 +528,53 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + (*m_RenderUpdateCallBackFn)(m_RenderUpdateCallBackCtx, m_sourceRect, m_destRect); + + CRect old = g_graphicsContext.GetScissors(); ++ RESOLUTION res = GetResolution(); ++ int iWidth = CDisplaySettings::Get().GetResolutionInfo(res).iWidth; ++ int iHeight = CDisplaySettings::Get().GetResolutionInfo(res).iHeight; + + g_graphicsContext.BeginPaint(); ++ if (clear) ++ { ++ glScissor(0, ++ 0, ++ iWidth, ++ iHeight); ++ glClearColor(GLfloat(0.0), GLfloat(0.0), GLfloat(0.0), 0); ++ glClear(GL_COLOR_BUFFER_BIT); ++ } ++ + g_graphicsContext.SetScissors(m_destRect); ++ /* CLog::Log(LOGDEBUG, "%s - m_destRect : %f %f %f %f\n", ++ __FUNCTION__, m_destRect.x1, m_destRect.x2, m_destRect.y1,m_destRect.y2);*/ + +- glEnable(GL_BLEND); +- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +- glClearColor(0, 0, 0, 0); ++ ++/* glEnable(GL_BLEND); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/ ++ glClearColor(GLfloat(2.0/31.0), GLfloat(2.0/63.0), GLfloat(2.0/31.0), 0); + glClear(GL_COLOR_BUFFER_BIT); + + g_graphicsContext.SetScissors(old); + g_graphicsContext.EndPaint(); ++ ++#ifdef HAS_IMXVPU ++ // FIXME : move in its own render mode instead of mixup with BYPASS ++ if (m_format == RENDER_FMT_IMX) ++ { ++ int index = m_iYV12RenderBuffer; ++ struct v4l2_crop crop; ++ crop.c.top = (int)m_destRect.y1; ++ crop.c.left = (int)m_destRect.x1; ++ crop.c.width = (int)(m_destRect.x2 - m_destRect.x1); ++ crop.c.height = (int)(m_destRect.y2 - m_destRect.y1); ++ CIMXOutputFrame *imxPicture = m_buffers[index].imxOutputFrame; ++ if (imxPicture != NULL) ++ { ++ imxPicture->Render(crop); ++ m_buffers[index].imxOutputFrame = NULL; ++ } ++ } + return; ++#endif + } + + // this needs to be checked after texture validation +@@ -598,6 +663,9 @@ unsigned int CLinuxRendererGLES::PreInit() + #ifdef HAVE_VIDEOTOOLBOXDECODER + m_formats.push_back(RENDER_FMT_CVBREF); + #endif ++#ifdef HAS_IMXVPU ++ m_formats.push_back(RENDER_FMT_IMX); ++#endif + #ifdef HAS_LIBSTAGEFRIGHT + m_formats.push_back(RENDER_FMT_EGLIMG); + #endif +@@ -723,6 +791,13 @@ void CLinuxRendererGLES::LoadShaders(int field) + m_renderMethod = RENDER_CVREF; + break; + } ++ else if (m_format == RENDER_FMT_IMX) ++ { ++ CLog::Log(LOGNOTICE, "GL: IMX format Uses BYPASS render method"); ++ m_renderMethod = RENDER_BYPASS; ++ break; ++ } ++ + #if defined(TARGET_DARWIN_IOS) + else if (ios_version < 5.0 && m_format == RENDER_FMT_YUV420P) + { +@@ -893,6 +968,18 @@ void CLinuxRendererGLES::ReleaseBuffer(int idx) + } + } + #endif ++#ifdef HAS_IMXVPU ++ if (buf.imxOutputFrame != NULL) ++ { ++ // If we take that branch the buffer was not queued to V4L2 ++ // So release the picture now so that VPU will be given ++ // the buffer back as soon as next ::Decode() call ++ buf.imxOutputFrame->Release(); ++ buf.imxOutputFrame = NULL; ++ } ++ return; ++#endif ++ + } + + void CLinuxRendererGLES::Render(DWORD flags, int index) +@@ -2691,6 +2778,15 @@ void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + CVBufferRetain(buf.cvBufferRef); + } + #endif ++ ++#ifdef HAS_IMXVPU ++void CLinuxRendererGLES::AddProcessor(CIMXOutputFrame *imx, int index) ++{ ++ YUVBUFFER &buf = m_buffers[index]; ++ buf.imxOutputFrame = imx; ++} ++#endif ++ + #ifdef HAS_LIBSTAGEFRIGHT + void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index) + { +@@ -2712,6 +2808,7 @@ void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKH + } + #endif + ++ + #if defined(TARGET_ANDROID) + void CLinuxRendererGLES::AddProcessor(CDVDMediaCodecInfo *mediacodec, int index) + { +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index 642cded..e58330a 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -42,6 +42,7 @@ namespace Shaders { class BaseVideoFilterShader; } + class COpenMaxVideo; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; ++class CIMXOutputFrame; + typedef std::vector Features; + + +@@ -166,6 +167,9 @@ class CLinuxRendererGLES : public CBaseRenderer + #ifdef HAS_LIBSTAGEFRIGHT + virtual void AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index); + #endif ++#ifdef HAS_IMXVPU ++ virtual void AddProcessor(CIMXOutputFrame *imx, int index); ++#endif + #if defined(TARGET_ANDROID) + // mediaCodec + virtual void AddProcessor(CDVDMediaCodecInfo *mediacodec, int index); +@@ -277,6 +281,9 @@ class CLinuxRendererGLES : public CBaseRenderer + #ifdef HAVE_VIDEOTOOLBOXDECODER + struct __CVBuffer *cvBufferRef; + #endif ++#ifdef HAS_IMXVPU ++ CIMXOutputFrame *imxOutputFrame; ++#endif + #ifdef HAS_LIBSTAGEFRIGHT + CDVDVideoCodecStageFright* stf; + EGLImageKHR eglimg; +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index f15e80d..d40e4f5 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -35,6 +35,7 @@ enum ERenderFormat { + RENDER_FMT_OMXEGL, + RENDER_FMT_CVBREF, + RENDER_FMT_BYPASS, ++ RENDER_FMT_IMX, + RENDER_FMT_EGLIMG, + RENDER_FMT_MEDIACODEC, + }; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 6832721..a9d071d 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -922,6 +922,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + else if(pic.format == RENDER_FMT_VAAPI) + m_pRenderer->AddProcessor(*pic.vaapi, index); + #endif ++#ifdef HAS_IMXVPU ++ else if(pic.format == RENDER_FMT_IMX) ++ m_pRenderer->AddProcessor(pic.imxOutputFrame, index); ++#endif + #ifdef HAS_LIBSTAGEFRIGHT + else if(pic.format == RENDER_FMT_EGLIMG) + m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +index 402093d..1de462e 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp +@@ -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" +@@ -190,7 +193,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne + #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 (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO)) +@@ -207,6 +214,15 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne + } + #endif + ++/*#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 --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 1553789..3e61edc 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -49,6 +49,7 @@ namespace VDPAU { class CVdpauRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; ++class CIMXOutputFrame; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; + typedef void* EGLImageKHR; +@@ -75,17 +76,19 @@ struct DVDVideoPicture + struct { + VAAPI::CHolder* vaapi; + }; +- + struct { + COpenMax *openMax; + OpenMaxVideoBuffer *openMaxBuffer; + }; +- + struct { + struct __CVBuffer *cvBufferRef; + }; + + struct { ++ CIMXOutputFrame *imxOutputFrame; ++ }; ++ ++ struct { + CDVDVideoCodecStageFright* stf; + EGLImageKHR eglimg; + }; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +new file mode 100644 +index 0000000..c0af493 +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -0,0 +1,1737 @@ ++/* ++ * Copyright (C) 2013 Stephan Rafin ++ * ++ * 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 ++ * . ++ * ++ */ ++ ++#include ++#include "DVDVideoCodecIMX.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "threads/SingleLock.h" ++#include "utils/log.h" ++#include "DVDClock.h" ++#include "mfw_gst_ts.h" ++#include "threads/Atomics.h" ++ ++//#define NO_V4L_RENDERING ++ ++#ifdef IMX_PROFILE ++static unsigned long long render_ts[30]; ++static unsigned long long get_time() ++{ ++ struct timespec ts; ++ unsigned long long now; ++ ++ clock_gettime(CLOCK_MONOTONIC, &ts); ++ now = (((unsigned long long)ts.tv_sec) * 1000000000ULL) + ++ ((unsigned long long)ts.tv_nsec); ++ ++ return now; ++} ++#endif ++ ++void CIMXOutputFrame::Render(struct v4l2_crop &crop) ++{ ++ CIMXRenderingFrames& renderingFrames = CIMXRenderingFrames::GetInstance(); ++ renderingFrames.Queue(this, crop); ++} ++ ++/* video device on which the video will be rendered (/dev/video17 => /dev/fb1) */ ++const char *CIMXRenderingFrames::m_v4lDeviceName = "/dev/video17"; ++static long sg_singleton_lock_variable = 0; ++CIMXRenderingFrames* CIMXRenderingFrames::m_instance = 0; ++ ++CIMXRenderingFrames& ++CIMXRenderingFrames::GetInstance() ++{ ++ CAtomicSpinLock lock(sg_singleton_lock_variable); ++ if( ! m_instance ) ++ { ++ m_instance = new CIMXRenderingFrames(); ++ } ++ return *m_instance; ++} ++ ++CIMXRenderingFrames::CIMXRenderingFrames() ++{ ++ m_ready = false; ++ m_v4lfd = -1; ++ m_virtAddr = NULL; ++ m_v4lBuffers = NULL; ++ memset(&m_crop, 0, sizeof(m_crop)); ++ m_crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ m_motionCtrl = -1; ++} ++ ++bool CIMXRenderingFrames::AllocateBuffers(const struct v4l2_format *format, int nbBuffers) ++{ ++ int ret, i; ++ struct v4l2_requestbuffers bufReq; ++ struct v4l2_format fmt; ++ struct v4l2_buffer v4lBuf; ++ struct v4l2_control ctrl; ++ ++ CSingleLock lock(m_renderingFramesLock); ++ if (m_ready) ++ { ++ CLog::Log(LOGERROR, "%s - Try to re-allocate buffers while previous buffers were not freed.\n", __FUNCTION__); ++ return false; ++ } ++ ++ m_v4lfd = open(m_v4lDeviceName, O_RDWR|O_NONBLOCK, 0); ++ if (m_v4lfd < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while trying to open %s.\n", __FUNCTION__, m_v4lDeviceName); ++ __ReleaseBuffers(); ++ return false; ++ } ++ ++ ret = ioctl(m_v4lfd, VIDIOC_S_FMT, format); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while setting V4L format (ret %d : %s).\n", __FUNCTION__, ret, strerror(errno)); ++ __ReleaseBuffers(); ++ return false; ++ } ++ ++ if (format->fmt.pix.field != V4L2_FIELD_NONE) ++ { ++ char * motion_entry; ++ motion_entry = getenv("IMX_DEINT_MOTION"); ++ if (motion_entry != NULL) ++ { ++ errno = 0; ++ m_motionCtrl = strtol(motion_entry, NULL, 10); ++ if (errno != 0) ++ m_motionCtrl = -1; ++ } ++ if (m_motionCtrl == -1) ++ m_motionCtrl = 2; /* Default value : 2 stands for high motion */ ++ ++ if ((m_motionCtrl >= 0) && (m_motionCtrl <=2)) ++ { ++ ctrl.id = V4L2_CID_MXC_MOTION; ++ ctrl.value = m_motionCtrl; ++ ret = ioctl (m_v4lfd, VIDIOC_S_CTRL, &ctrl); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while setting V4L motion (ret %d : %s).\n", __FUNCTION__, ret, strerror(errno)); ++ } ++ } ++ else ++ { ++ CLog::Log(LOGNOTICE, "%s - IMX_DEINT_MOTION set to %d. Disabling deinterlacing.\n", __FUNCTION__, m_motionCtrl); ++ m_motionCtrl = -2; ++ } ++ } ++ ++ fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ret = ioctl(m_v4lfd, VIDIOC_G_FMT, &fmt); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while getting V4L format (ret %d : %s).\n", __FUNCTION__, ret, strerror(errno)); ++ __ReleaseBuffers(); ++ return false; ++ } ++ ++ m_bufferNum = nbBuffers; ++ /* Alloc V4L2 buffers */ ++ memset(&bufReq, 0, sizeof(bufReq)); ++ bufReq.count = m_bufferNum; ++ bufReq.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ bufReq.memory = V4L2_MEMORY_MMAP; ++ ret = ioctl(m_v4lfd, VIDIOC_REQBUFS, &bufReq); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - %d Hw buffer allocation error (%d)\n", __FUNCTION__, bufReq.count, ret); ++ __ReleaseBuffers(); ++ return false; ++ } ++ CLog::Log(LOGDEBUG, "%s - %d Hw buffer of %d bytes allocated\n", __FUNCTION__, bufReq.count, fmt.fmt.pix.sizeimage); ++ ++ m_virtAddr = new void*[m_bufferNum]; ++ if (m_virtAddr == NULL) ++ { ++ CLog::Log(LOGERROR, "%s - Allocation failure (m_virtAddr table of %d elements)\n", __FUNCTION__, m_bufferNum); ++ __ReleaseBuffers(); ++ return false; ++ } ++ m_v4lBuffers = new v4l2_buffer[m_bufferNum]; ++ if (m_v4lBuffers == NULL) ++ { ++ CLog::Log(LOGERROR, "%s - Allocation failure (m_v4lBuffers table of %d elements)\n", __FUNCTION__, m_bufferNum); ++ __ReleaseBuffers(); ++ return false; ++ } ++ ++ for (i = 0 ; i < m_bufferNum; i++) ++ { ++ memset(&v4lBuf, 0, sizeof(v4lBuf)); ++ v4lBuf.index = i; ++ v4lBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ v4lBuf.memory = V4L2_MEMORY_MMAP; ++ ret = ioctl (m_v4lfd, VIDIOC_QUERYBUF, &v4lBuf); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error during 1st query of V4L buffer (ret %d : %s)\n", __FUNCTION__, ret, strerror(errno)); ++ return false; ++ } ++ m_v4lBuffers[i] = v4lBuf; ++ m_virtAddr[i] = NULL; ++ } ++ memset(&m_crop, 0, sizeof(m_crop)); ++ m_crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ m_pushedFrames = 0; ++ m_streamOn = false; ++ m_ready = true; ++ return true; ++} ++ ++void *CIMXRenderingFrames::GetVirtAddr(int idx) ++{ ++ struct v4l2_buffer v4lBuf; ++ int ret; ++ ++ CSingleLock lock(m_renderingFramesLock); ++ if (!m_ready) ++ return NULL; ++ if ((idx < 0) || (idx >= m_bufferNum)) ++ return NULL; ++ ++ if (m_virtAddr[idx] == NULL) ++ { ++ v4lBuf = m_v4lBuffers[idx]; ++ m_virtAddr[idx] = mmap(NULL, v4lBuf.length, PROT_READ | PROT_WRITE, MAP_SHARED, m_v4lfd, v4lBuf.m.offset); ++ ++ /* 2nd query to retrieve real Physical address after mmap (iMX6 bug) */ ++ ret = ioctl (m_v4lfd, VIDIOC_QUERYBUF, &v4lBuf); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error during 2nd query of V4L buffer (ret %d : %s)\n", __FUNCTION__, ret, strerror(errno)); ++ } ++ m_v4lBuffers[idx] = v4lBuf; ++ } ++ return m_virtAddr[idx]; ++} ++ ++void *CIMXRenderingFrames::GetPhyAddr(int idx) ++{ ++ ++ CSingleLock lock(m_renderingFramesLock); ++ if (!m_ready) ++ return NULL; ++ if ((idx < 0) || (idx >= m_bufferNum)) ++ return NULL; ++ ++ return (void *)m_v4lBuffers[idx].m.offset; ++} ++ ++int CIMXRenderingFrames::FindBuffer(void *phyAddr) ++{ ++ int i; ++ ++ CSingleLock lock(m_renderingFramesLock); ++ if (!m_ready) ++ return -1; ++ ++ for (i = 0; i < m_bufferNum; i++) ++ { ++ if (m_v4lBuffers[i].m.offset == (unsigned int)phyAddr) ++ { ++ // CLog::Log(LOGNOTICE, "%s - found buffer OK %d!\n", __FUNCTION__, i); ++ return i; ++ } ++ } ++ return -1; ++} ++ ++int CIMXRenderingFrames::DeQueue(bool wait) ++{ ++ int ret; ++ int status; ++ struct v4l2_buffer buf; ++ ++ CSingleLock lock(m_renderingFramesLock); ++ if (!m_ready) ++ { ++ CLog::Log(LOGNOTICE, "%s - Cannot dequeue frame as buffers were released !\n", ++ __FUNCTION__); ++ return -1; ++ } ++ if (!m_streamOn) ++ { ++ return -1; ++ } ++ ++ if (wait) ++ { ++ status = fcntl(m_v4lfd, F_GETFL); ++ fcntl(m_v4lfd, F_SETFL, status & (~O_NONBLOCK)); ++ } ++ buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ buf.memory = V4L2_MEMORY_MMAP; ++ ret = ioctl(m_v4lfd, VIDIOC_DQBUF, &buf); ++ if (wait) ++ { ++ fcntl(m_v4lfd, F_SETFL, status | O_NONBLOCK); ++ } ++ if (ret != 0) ++ { ++ if (errno != EAGAIN) ++ CLog::Log(LOGERROR, "%s - Dequeue buffer error (ret %d : %s)\n", ++ __FUNCTION__, ret, strerror(errno)); ++ return -1; ++ } ++ ++#ifdef IMX_PROFILE ++ CLog::Log(LOGDEBUG, "%s - Time render to dequeue (%d) %llu\n", ++ __FUNCTION__, buf.index, get_time() - render_ts[buf.index]); ++#endif ++// CLog::Log(LOGERROR, "%s dequeued retuns (%d)\n", __FUNCTION__, buf.index); ++ ++ return buf.index; ++} ++ ++void CIMXRenderingFrames::Queue(CIMXOutputFrame *picture, struct v4l2_crop &destRect) ++{ ++ /* Warning : called from renderer thread ++ * Especially do not call any VPU functions as they are not thread safe ++ */ ++ ++ int ret, type; ++ struct timeval queue_ts; ++ int stream_trigger; ++ bool crop_update = false; ++ ++ CSingleLock lock(m_renderingFramesLock); ++ if (!m_ready) ++ { ++ CLog::Log(LOGNOTICE, "%s - Cannot queue frame as buffers were released !\n", ++ __FUNCTION__); ++ return; ++ } ++ ++ /*CLog::Log(LOGDEBUG, "%s - queuing frame %d - picture adress : %p\n", ++ __FUNCTION__, picture->v4l2BufferIdx, picture);*/ ++ ++ if ((picture->v4l2BufferIdx < 0) || (picture->v4l2BufferIdx >= m_bufferNum)) ++ { ++ CLog::Log(LOGERROR, "%s - Invalid buffer index : %d - picture address : %p\n", ++ __FUNCTION__, picture->v4l2BufferIdx, picture); ++ return; ++ } ++ ++ /* Set field type for each buffer otherwise the mxc_vout driver reverts to progressive */ ++ switch (picture->field) ++ { ++ case VPU_FIELD_TB: ++ m_v4lBuffers[picture->v4l2BufferIdx].field = V4L2_FIELD_INTERLACED_TB; ++ break; ++ case VPU_FIELD_BT: ++ m_v4lBuffers[picture->v4l2BufferIdx].field= V4L2_FIELD_INTERLACED_BT; ++ break; ++ case VPU_FIELD_NONE: ++ default: ++ m_v4lBuffers[picture->v4l2BufferIdx].field = V4L2_FIELD_NONE; ++ break; ++ } ++ /* In case deinterlacing is forced to disabled */ ++ if (m_motionCtrl == -2) ++ m_v4lBuffers[picture->v4l2BufferIdx].field = V4L2_FIELD_NONE; ++ ++ /* mxc_vout driver does not display immediatly ++ * if timestamp is set to 0 ++ * (instead this driver expects a 30fps rate) ++ * So we explicitly set current time for immediate display ++ */ ++ gettimeofday (&queue_ts, NULL); ++ m_v4lBuffers[picture->v4l2BufferIdx].timestamp = queue_ts; ++ ++#ifndef NO_V4L_RENDERING ++ ret = ioctl(m_v4lfd, VIDIOC_QBUF, &m_v4lBuffers[picture->v4l2BufferIdx]); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - V4L Queue buffer failed (ret %d : %s)\n", ++ __FUNCTION__, ret, strerror(errno)); ++ /* If it fails odds are very high picture is invalid so just exit now */ ++ return; ++ } ++ else ++ { ++ m_pushedFrames++; ++ } ++ ++ /* Force cropping dimensions to be aligned */ ++ destRect.c.top &= 0xFFFFFFF8; ++ destRect.c.left &= 0xFFFFFFF8; ++ destRect.c.width &= 0xFFFFFFF8; ++ destRect.c.height &= 0xFFFFFFF8; ++ if ((m_crop.c.top != destRect.c.top) || ++ (m_crop.c.left != destRect.c.left) || ++ (m_crop.c.width != destRect.c.width) || ++ (m_crop.c.height != destRect.c.height)) ++ { ++ CLog::Log(LOGNOTICE, "%s - Newcrop : %d % d %d %d\n", ++ __FUNCTION__, destRect.c.top, destRect.c.left, destRect.c.width, destRect.c.height); ++ m_crop.c = destRect.c; ++ crop_update = true; ++ } ++ ++ if (!m_streamOn) ++ { ++ if (picture->field == VPU_FIELD_NONE) ++ stream_trigger = 1; ++ else { ++ if (m_motionCtrl < 2) ++ stream_trigger = 3; ++ else ++ stream_trigger = 2; ++ } ++ ++ if (m_pushedFrames >= stream_trigger) { ++ CLog::Log(LOGDEBUG, "%s - Motion control is : %d - Number of required frames before streaming : %d\n", ++ __FUNCTION__, m_motionCtrl, stream_trigger); ++ ++ type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ret = ioctl(m_v4lfd, VIDIOC_STREAMON, &type); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - V4L Stream ON failed (ret %d : %s)\n", ++ __FUNCTION__, ret, strerror(errno)); ++ } ++ else ++ { ++ CLog::Log(LOGDEBUG, "%s - V4L Stream ON OK\n", ++ __FUNCTION__); ++ m_streamOn = true; ++ } ++ /* We have to repeat crop command after streamon for some vids ++ * FIXME : Check why in drivers... ++ */ ++ ret = ioctl(m_v4lfd, VIDIOC_S_CROP, &m_crop); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - S_CROP failed (ret %d : %s)\n", ++ __FUNCTION__, ret, strerror(errno)); ++ } ++ } ++ } ++ else ++ { ++ if (crop_update) ++ { ++ ret = ioctl(m_v4lfd, VIDIOC_S_CROP, &m_crop); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "%s - S_CROP failed (ret %d : %s)\n", ++ __FUNCTION__, ret, strerror(errno)); ++ } ++ } ++ } ++#endif ++ ++#ifdef IMX_PROFILE ++ render_ts[picture->v4l2BufferIdx] = get_time(); ++ CLog::Log(LOGDEBUG, "%s - Time push to render (%d) %llu\n", ++ __FUNCTION__, picture->v4l2BufferIdx, render_ts[picture->v4l2BufferIdx] - picture->pushTS); ++#endif ++} ++ ++void CIMXRenderingFrames::ReleaseBuffers() ++{ ++ CSingleLock lock(m_renderingFramesLock); ++ if (!m_ready) ++ { ++ CLog::Log(LOGERROR, "%s - AllocateBuffers was not previously called\n", __FUNCTION__); ++ return; ++ } ++ __ReleaseBuffers(); ++} ++ ++/* Note : Has to be called with m_renderingFramesLock held */ ++void CIMXRenderingFrames::__ReleaseBuffers() ++{ ++ int type, i; ++ ++ if (m_v4lfd >= 0) ++ { ++ /* stream off */ ++ type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ ioctl (m_v4lfd, VIDIOC_STREAMOFF, &type); ++ m_streamOn = false; ++ } ++ ++ if (m_virtAddr != NULL) ++ { ++ for (i = 0; i < m_bufferNum; i++) ++ { ++ if (m_virtAddr[i] != NULL) ++ munmap (m_virtAddr[i], m_v4lBuffers[i].length); ++ } ++ delete m_virtAddr; ++ m_virtAddr = NULL; ++ } ++ ++ if (m_v4lfd >= 0) ++ { ++ /* Close V4L2 device */ ++ close(m_v4lfd); ++ m_v4lfd = -1; ++ } ++ ++ if (m_v4lBuffers != NULL) ++ { ++ delete m_v4lBuffers; ++ m_v4lBuffers = NULL; ++ } ++ m_bufferNum = 0; ++ m_pushedFrames = 0; ++ m_ready = false; ++ m_motionCtrl = -1; ++} ++ ++/* 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)) ++#define min(a, b) (aGetClock() / DVD_TIME_BASE; ++ ++ return clock_pts; ++} ++ ++void CDVDVideoCodecIMX::FlushDecodedFrames(void) ++{ ++ DVDVideoPicture DVDFrame; ++ while (m_decodedFrames.size() > 0) ++ { ++ DVDFrame = m_decodedFrames.front(); ++ VpuReleaseBufferV4L(DVDFrame.imxOutputFrame->v4l2BufferIdx); ++ m_decodedFrames.pop(); ++ } ++} ++ ++bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) ++{ ++ int i, size; ++ unsigned char * ptr; ++ VpuMemDesc vpuMem; ++ VpuDecRetCode ret; ++ ++ for(i=0; inSubBlockNum; i++) ++ { ++ size = pMemBlock->MemSubBlock[i].nAlignment + pMemBlock->MemSubBlock[i].nSize; ++ if (pMemBlock->MemSubBlock[i].MemType == VPU_MEM_VIRT) ++ { // Allocate standard virtual memory ++ ptr = (unsigned char *)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.virtMem[m_decMemInfo.nVirtNum] = (unsigned int)ptr; ++ m_decMemInfo.nVirtNum++; ++ } ++ 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.phyMem_phyAddr[m_decMemInfo.nPhyNum] = (unsigned int)vpuMem.nPhyAddr; ++ m_decMemInfo.phyMem_virtAddr[m_decMemInfo.nPhyNum] = (unsigned int)vpuMem.nVirtAddr; ++ m_decMemInfo.phyMem_cpuAddr[m_decMemInfo.nPhyNum] = (unsigned int)vpuMem.nCpuAddr; ++ m_decMemInfo.phyMem_size[m_decMemInfo.nPhyNum] = size; ++ m_decMemInfo.nPhyNum++; ++ } ++ } ++ ++ return true; ++ ++AllocFailure: ++ VpuFreeBuffers(); ++ return false; ++} ++ ++bool CDVDVideoCodecIMX::VpuFreeBuffers(void) ++{ ++ int i; ++ VpuMemDesc vpuMem; ++ VpuDecRetCode vpuRet; ++ bool ret = true; ++ ++ //free virtual mem ++ for(i=0; ipDisplayFrameBuf; ++ CIMXOutputFrame *outputFrame; ++ int i; ++ double pts; ++ DVDVideoPicture DVDFrame; ++ ++ // FIXME pts = (double)TSManagerSend2(m_tsm, frameBuffer) / (double)1000.0; ++ pts = (double)TSManagerSend(m_tsm) / (double)1000.0; ++ /* Find Frame given physical address */ ++ i = m_renderingFrames.FindBuffer(frameBuffer->pbufY); ++ if (i == -1) ++ { ++ CLog::Log(LOGERROR, "%s - V4L buffer not found\n", __FUNCTION__); ++ return false; ++ } ++ if (m_outputBuffers[i].used()) ++ { ++ CLog::Log(LOGERROR, "%s - Try to reuse buffer which was not dequeued !\n", __FUNCTION__); ++ return false; ++ } ++ ++ /* Store the pointer to be able to invoke VPU_DecOutFrameDisplayed when the buffer will be dequeued */ ++ m_outputBuffers[i].store(frameBuffer, m_frameCounter++); ++ ++ outputFrame = &m_outputBuffers[i].outputFrame; ++ outputFrame->v4l2BufferIdx = i; ++ outputFrame->field = frameInfo->eFieldType; ++ outputFrame->picCrop = frameInfo->pExtInfo->FrmCropRect; ++ outputFrame->nQ16ShiftWidthDivHeightRatio = frameInfo->pExtInfo->nQ16ShiftWidthDivHeightRatio; ++ DVDFrame.imxOutputFrame = outputFrame; ++ ++ DVDFrame.pts = pts; ++ DVDFrame.dts = DVD_NOPTS_VALUE; ++ /* ++ m_outputFrame.iWidth = frameInfo->pExtInfo->nFrmWidth; ++ m_outputFrame.iHeight = frameInfo->pExtInfo->nFrmHeight; ++ */ ++ DVDFrame.iWidth = frameInfo->pExtInfo->FrmCropRect.nRight - frameInfo->pExtInfo->FrmCropRect.nLeft; ++ DVDFrame.iHeight = frameInfo->pExtInfo->FrmCropRect.nBottom - frameInfo->pExtInfo->FrmCropRect.nTop; ++ DVDFrame.format = RENDER_FMT_IMX; ++ ++ m_decodedFrames.push(DVDFrame); ++ if (m_decodedFrames.size() > IMX_MAX_QUEUE_SIZE) ++ { ++ CLog::Log(LOGERROR, "%s - Too many enqueued decoded frames : %d (Max %d)\n", __FUNCTION__, m_decodedFrames.size(), IMX_MAX_QUEUE_SIZE); ++ } ++ ++#ifdef IMX_PROFILE ++ DVDFrame.imxOutputFrame->pushTS = get_time(); ++ CLog::Log(LOGDEBUG, "%s - push (%i) Time between push %llu\n", ++ __FUNCTION__, i, DVDFrame.imxOutputFrame->pushTS - previous_ts); ++ previous_ts =DVDFrame.imxOutputFrame->pushTS; ++#endif ++ ++ return true; ++} ++ ++int CDVDVideoCodecIMX::GetAvailableBufferNb(void) ++{ ++ int i, nb; ++ ++ nb = 0; ++ for (i = 0; i < m_vpuFrameBufferNum; i++) ++ { ++ if (!m_outputBuffers[i].used()) ++ nb++; ++ } ++ return nb; ++} ++ ++bool CDVDVideoCodecIMX::VpuReleaseBufferV4L(int idx) ++{ ++ if (idx < 0 || idx >= m_vpuFrameBufferNum) ++ { ++ CLog::Log(LOGERROR, "%s - Invalid index - idx : %d\n", __FUNCTION__, idx); ++ return false; ++ } ++ ++ /*CLog::Log(LOGDEBUG, "%s - idx : %d - frame : %d\n", __FUNCTION__, ++ idx, m_outputBuffers[idx].frameNo);*/ ++ ++ VPU_DecOutFrameDisplayed(m_vpuHandle, m_outputBuffers[idx].buffer); ++ m_outputBuffers[idx].clear(); ++ return true; ++} ++ ++/* Dequeue queued frames and free the corresponding VPU buffers */ ++bool CDVDVideoCodecIMX::VpuDeQueueFrame(bool wait) ++{ ++ int idx, i, frameNo; ++ ++ idx = m_renderingFrames.DeQueue(wait); ++ if (idx != -1) ++ { ++ if (!m_outputBuffers[idx].used()) ++ { ++ CLog::Log(LOGERROR, "%s - WTF : associated buffer does not exist anymore\n", ++ __FUNCTION__); ++ return true; ++ } ++ else ++ { ++ frameNo = m_outputBuffers[idx].frameNo(); ++ VpuReleaseBufferV4L(idx); ++ if (frameNo > 0) ++ { ++ /* Release buffers which are not used anymore and were ++ * queued before the idx buffer that has just been dequeued*/ ++ for (i = 0; i < m_vpuFrameBufferNum; ++i) ++ { ++ if (m_outputBuffers[i].expired(frameNo)) ++ { ++ CLog::Log(LOGNOTICE, "%s - Release expired buffer - idx : %d\n", __FUNCTION__, i); ++ VpuReleaseBufferV4L(i); ++ } ++ } ++ } ++ return true; ++ } ++ } ++ else ++ { ++#ifdef NO_V4L_RENDERING ++ int i; ++ for (i = 0; i < m_vpuFrameBufferNum; i++) ++ { ++ if (m_outputBuffers[i].used()) ++ { ++ VpuReleaseBufferV4L(idx); ++ } ++ } ++#endif ++ return false; ++ } ++} ++ ++CDVDVideoCodecIMX::CDVDVideoCodecIMX() : m_renderingFrames(CIMXRenderingFrames::GetInstance()) ++{ ++ m_pFormatName = "iMX-xxx"; ++ memset(&m_decMemInfo, 0, sizeof(DecMemInfo)); ++ m_vpuHandle = 0; ++ m_vpuFrameBuffers = NULL; ++ m_outputBuffers = NULL; ++ m_extraMem = NULL; ++ m_vpuFrameBufferNum = 0; ++ m_tsSyncRequired = true; ++ m_dropState = false; ++ m_tsm = NULL; ++ m_convert_bitstream = false; ++ m_frameCounter = 0; ++ m_usePTS = true; ++ if (getenv("IMX_NOPTS") != NULL) ++ { ++ m_usePTS = false; ++ } ++} ++ ++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) ++ { ++ unsigned int i; ++ char buf[4096]; ++ ++ for (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_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: ++ m_decOpenParam.CodecFormat = VPU_V_AVC; ++ m_pFormatName = "iMX-h264"; ++ if (hints.extradata) ++ { ++ if ( *(char*)hints.extradata == 1 ) ++ m_convert_bitstream = bitstream_convert_init(hints.extradata,hints.extrasize); ++ } ++ 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_MSMPEG4V3: ++ m_decOpenParam.CodecFormat = VPU_V_XVID; /* VPU_V_DIVX3 */ ++ m_pFormatName = "iMX-divx3"; ++ 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; ++ int i; ++ bool VPU_loaded = m_vpuHandle; ++ ++ FlushDecodedFrames(); ++ 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; ++ } ++ ++ VpuFreeBuffers(); ++ ++ if (m_outputBuffers != NULL) ++ { ++ while (VpuDeQueueFrame(false)); ++ m_renderingFrames.ReleaseBuffers(); ++ RestoreFB(); ++ delete m_outputBuffers; ++ m_outputBuffers = NULL; ++ } ++ ++ /* Free extramem */ ++ if (m_extraMem != NULL) ++ { ++ for (i = 0; i < m_vpuFrameBufferNum; i++) ++ { ++ if (m_extraMem[i].nSize > 0) ++ { ++ ret = VPU_DecFreeMem(&m_extraMem[i]); ++ if (ret != VPU_DEC_RET_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s - Release extra mem failed with error code %d.\n", __FUNCTION__, ret); ++ } ++ m_extraMem[i].nSize = 0; ++ } ++ } ++ delete m_extraMem; ++ m_extraMem = NULL; ++ } ++ 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_tsm != NULL) ++ { ++ destroyTSManager(m_tsm); ++ m_tsm = NULL; ++ } ++ ++ if (m_convert_bitstream) ++ { ++ if (m_sps_pps_context.sps_pps_data) ++ { ++ free(m_sps_pps_context.sps_pps_data); ++ m_sps_pps_context.sps_pps_data = NULL; ++ } ++ } ++ return; ++} ++ ++int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) ++{ ++ VpuDecFrameLengthInfo frameLengthInfo; ++ VpuBufferNode inData; ++ VpuDecRetCode ret; ++ VpuDecOutFrameInfo frameInfo; ++ int decRet = 0; ++ int retStatus = 0; ++ int demuxer_bytes = iSize; ++ uint8_t *demuxer_content = pData; ++ bool bitstream_convered = false; ++ bool retry = false; ++ ++#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; ++ } ++ ++#ifdef IMX_PROFILE ++ current = get_time(); ++ 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 ++ ++/* FIXME tests ++ CLog::Log(LOGDEBUG, "%s - demux size : %d dts : %f - pts : %f - %x %x %x %x\n", __FUNCTION__, iSize, dts, pts, ((unsigned int *)pData)[0], ((unsigned int *)pData)[1], ((unsigned int *)pData)[2], ((unsigned int *)pData)[3]); ++ ((unsigned int *)pData)[0] = htonl(iSize-4); ++*/ ++ ++ while (VpuDeQueueFrame(false)); ++ ++ if (pData && iSize) ++ { ++ if (m_convert_bitstream) ++ { ++ // convert demuxer packet from bitstream to bytestream (AnnexB) ++ int bytestream_size = 0; ++ uint8_t *bytestream_buff = NULL; ++ ++ if (!bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size)) ++ { ++ CLog::Log(LOGERROR, "%s - bitstream convert error...\n", __FUNCTION__); ++ return VC_ERROR; ++ } ++ ++ if (bytestream_buff && (bytestream_size > 0)) ++ { ++ bitstream_convered = true; ++ demuxer_bytes = bytestream_size; ++ demuxer_content = bytestream_buff; ++ } ++ } ++ ++ if (pts != DVD_NOPTS_VALUE) ++ { ++ if (m_tsSyncRequired) ++ { ++ m_tsSyncRequired = false; ++ resyncTSManager(m_tsm, llrint(pts) * 1000, MODE_AI); ++ } ++ //TSManagerReceive2(m_tsm, llrint(pts) * 1000, iSize); ++ TSManagerReceive(m_tsm, llrint(pts) * 1000); ++ } ++ else ++ { ++ //If no pts but dts available (AVI container for instance) then use this one ++ if (dts != DVD_NOPTS_VALUE) ++ { ++ if (m_tsSyncRequired) ++ { ++ m_tsSyncRequired = false; ++ resyncTSManager(m_tsm, llrint(dts) * 1000, MODE_AI); ++ } ++ //TSManagerReceive2(m_tsm, llrint(dts) * 1000, iSize); ++ TSManagerReceive(m_tsm, llrint(dts) * 1000); ++ } ++ } ++ ++ 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; ++ } ++ ++ do // Decode as long as the VPU consumes data ++ { ++ retry = false; ++#ifdef IMX_PROFILE ++ before_dec = get_time(); ++#endif ++ 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, get_time() - 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); ++ } ++ // FIXME TSManagerValid2(m_tsm, frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength, frameLengthInfo.pFrame); ++ //CLog::Log(LOGDEBUG, "%s - size : %d - key consummed : %x\n", __FUNCTION__, frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength, frameLengthInfo.pFrame); ++ }//VPU_DEC_ONE_FRM_CONSUMED ++ ++ if ((decRet & VPU_DEC_OUTPUT_DIS) || ++ (decRet & VPU_DEC_OUTPUT_MOSAIC_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, &frameInfo); ++ if(ret != VPU_DEC_RET_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s - VPU Cannot get output frame(%d).\n", __FUNCTION__, ret); ++ goto out_error; ++ } ++ if (VpuPushFrame(&frameInfo)) ++ { ++ retStatus |= VC_PICTURE; ++ } ++ } //VPU_DEC_OUTPUT_DIS ++ ++ if (decRet & VPU_DEC_OUTPUT_REPEAT) ++ { ++ TSManagerSend(m_tsm); ++ CLog::Log(LOGDEBUG, "%s - Frame repeat.\n", __FUNCTION__); ++ } ++ if (decRet & VPU_DEC_OUTPUT_DROPPED) ++ { ++ TSManagerSend(m_tsm); ++ 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) ++ { ++ TSManagerSend(m_tsm); ++ CLog::Log(LOGDEBUG, "%s - Frame skipped.\n", __FUNCTION__); ++ } ++ if (decRet & VPU_DEC_FLUSH) ++ { ++ CLog::Log(LOGNOTICE, "%s - VPU requires a flush.\n", __FUNCTION__); ++ ret = VPU_DecFlushAll(m_vpuHandle); ++ if (ret != VPU_DEC_RET_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s - VPU flush failed(%d).\n", __FUNCTION__, ret); ++ } ++ retStatus = VC_FLUSHED; ++ } ++ if (decRet & VPU_DEC_OUTPUT_EOS) ++ { ++ CLog::Log(LOGNOTICE, "%s - EOS encountered.\n", __FUNCTION__); ++ } ++ if (decRet & VPU_DEC_NO_ENOUGH_INBUF) ++ { ++ // We are done with VPU decoder that time ++ break; ++ } ++ if (!(decRet & VPU_DEC_INPUT_USED)) ++ { ++ CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize); ++ TSManagerSend(m_tsm); ++ } ++ ++ ++ if (!(decRet & VPU_DEC_OUTPUT_DIS) && ++ (inData.nSize != 0)) ++ { ++ /* 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; ++ retry = true; ++ } ++ ++ } while (retry == true); ++ } //(pData && iSize) ++ ++ if (GetAvailableBufferNb() > (m_vpuFrameBufferNum - m_extraVpuBuffers)) ++ { ++ retStatus |= VC_BUFFER; ++ } ++ else ++ { ++ if (retStatus == 0) { ++ /* No Picture ready and Not enough VPU buffers. It should NOT happen so log dedicated error */ ++ CLog::Log(LOGERROR, "%s - Not hw buffer available. Waiting for 2ms\n", __FUNCTION__); ++ /* Lets wait for the IPU to free a buffer. Anyway we have several decoded frames ready */ ++ usleep(2000); ++ } ++ } ++ ++ if (bitstream_convered) ++ free(demuxer_content); ++ ++ retStatus &= (~VC_PICTURE); ++ if (m_decodedFrames.size() >= IMX_MAX_QUEUE_SIZE) ++ retStatus |= VC_PICTURE; ++ ++#ifdef IMX_PROFILE ++ CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, get_time() - previous); ++#endif ++ return retStatus; ++ ++out_error: ++ if (bitstream_convered) ++ free(demuxer_content); ++ return VC_ERROR; ++} ++ ++void CDVDVideoCodecIMX::Reset() ++{ ++ int ret; ++ ++ CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); ++ ++ /* We have to resync timestamp manager */ ++ m_tsSyncRequired = true; ++ ++ /* Flush decoded frames */ ++ FlushDecodedFrames(); ++ ++ /* 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() ++{ ++ // Note : It is useless if CLinuxRendererGLES::GetProcessorSize returns 0 for RENDER_FMT_IMX ++ return min(3, m_extraVpuBuffers / 2); ++} ++ ++ ++bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) ++{ ++ double currentPlayerPts; ++ double ts = DVD_NOPTS_VALUE; ++ DVDVideoPicture DVDFrame; ++ ++ if (m_decodedFrames.size() == 0) ++ { ++ CLog::Log(LOGERROR, "%s called while no picture ready\n", __FUNCTION__); ++ return false; ++ } ++ ++ /* Retrieve oldest decoded frame */ ++ DVDFrame = m_decodedFrames.front(); ++ m_decodedFrames.pop(); ++ //CLog::Log(LOGNOTICE, "%s - buffer(%d)\n", __FUNCTION__, DVDFrame.imxOutputFrame->v4l2BufferIdx); ++ ++ pDvdVideoPicture->iFlags &= DVP_FLAG_DROPPED; ++ if ((pDvdVideoPicture->iFlags != 0) || (m_dropState)) ++ { ++ CLog::Log(LOGNOTICE, "%s - Flushing video picture\n", __FUNCTION__); ++ pDvdVideoPicture->iFlags = DVP_FLAG_DROPPED; ++ VpuReleaseBufferV4L(DVDFrame.imxOutputFrame->v4l2BufferIdx); ++ DVDFrame.imxOutputFrame = NULL; ++ } ++ else ++ { ++ ts = DVDFrame.pts; ++ currentPlayerPts = GetPlayerPtsSeconds() * (double)DVD_TIME_BASE; ++ if (currentPlayerPts > ts) ++ { ++ CLog::Log(LOGERROR, "%s - player is ahead of time (%f)\n", __FUNCTION__, currentPlayerPts - ts); ++ } ++ //CLog::Log(LOGINFO, "%s - idx : %d - delta call %f - delta ts %f \n", __FUNCTION__, outputFrame.v4l2_buffer->index,ts - previous, ts - currentPlayerPts); ++ } ++ ++#ifdef NO_V4L_RENDERING ++ if (!m_dropState) ++ { ++ VpuReleaseBufferV4L(DVDFrame.imxOutputFrame->v4l2BufferIdx); ++ } ++#endif ++ ++ pDvdVideoPicture->pts = DVDFrame.pts; ++ if (!m_usePTS) ++ { ++ pDvdVideoPicture->pts = DVD_NOPTS_VALUE; ++ } ++ pDvdVideoPicture->dts = DVDFrame.dts; ++ pDvdVideoPicture->iWidth = DVDFrame.iWidth; ++ pDvdVideoPicture->iHeight = DVDFrame.iHeight; ++ if (m_dropState) ++ { ++ pDvdVideoPicture->iDisplayWidth = DVDFrame.iWidth; ++ pDvdVideoPicture->iDisplayHeight = DVDFrame.iHeight; ++ } ++ else ++ { ++ pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * DVDFrame.imxOutputFrame->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; ++ pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; ++ } ++ pDvdVideoPicture->format = DVDFrame.format; ++ pDvdVideoPicture->imxOutputFrame = DVDFrame.imxOutputFrame; ++ ++#ifdef V4L_OUTPUT_PROFILE ++ CLog::Log(LOGDEBUG, "%s - QF : %d - HWfre : %d/%d/%d\n", ++ (int)m_decodedFrames.size(), GetAvailableBufferNb(), ++ m_extraVpuBuffers, m_vpuFrameBufferNum); ++#endif ++ 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; ++ CLog::Log(LOGNOTICE, "%s : %d\n", __FUNCTION__, bDrop); ++ } ++} ++ ++/* bitstream convert : Shameless copy from openmax */ ++/* TODO : Have a look at it as the malloc/copy/free strategy is obviously not the most efficient one */ ++ ++bool CDVDVideoCodecIMX::bitstream_convert_init(void *in_extradata, int in_extrasize) ++{ ++ // based on h264_mp4toannexb_bsf.c (ffmpeg) ++ // which is Copyright (c) 2007 Benoit Fouet ++ // and Licensed GPL 2.1 or greater ++ ++ m_sps_pps_size = 0; ++ m_sps_pps_context.sps_pps_data = NULL; ++ ++ // nothing to filter ++ if (!in_extradata || in_extrasize < 6) ++ return false; ++ ++ uint16_t unit_size; ++ uint32_t total_size = 0; ++ uint8_t *out = NULL, unit_nb, sps_done = 0; ++ const uint8_t *extradata = (uint8_t*)in_extradata + 4; ++ static const uint8_t nalu_header[4] = {0, 0, 0, 1}; ++ ++ // retrieve length coded size ++ m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1; ++ if (m_sps_pps_context.length_size == 3) ++ return false; ++ ++ // retrieve sps and pps unit(s) ++ unit_nb = *extradata++ & 0x1f; // number of sps unit(s) ++ if (!unit_nb) ++ { ++ unit_nb = *extradata++; // number of pps unit(s) ++ sps_done++; ++ } ++ while (unit_nb--) ++ { ++ unit_size = extradata[0] << 8 | extradata[1]; ++ total_size += unit_size + 4; ++ if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) ) ++ { ++ free(out); ++ return false; ++ } ++ uint8_t* new_out = (uint8_t*)realloc(out, total_size); ++ if (new_out) ++ { ++ out = new_out; ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out", __FUNCTION__); ++ free(out); ++ return false; ++ } ++ ++ memcpy(out + total_size - unit_size - 4, nalu_header, 4); ++ memcpy(out + total_size - unit_size, extradata + 2, unit_size); ++ extradata += 2 + unit_size; ++ ++ if (!unit_nb && !sps_done++) ++ unit_nb = *extradata++; // number of pps unit(s) ++ } ++ ++ m_sps_pps_context.sps_pps_data = out; ++ m_sps_pps_context.size = total_size; ++ m_sps_pps_context.first_idr = 1; ++ ++ return true; ++} ++ ++bool CDVDVideoCodecIMX::bitstream_convert(BYTE* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size) ++{ ++ // based on h264_mp4toannexb_bsf.c (ffmpeg) ++ // which is Copyright (c) 2007 Benoit Fouet ++ // and Licensed GPL 2.1 or greater ++ ++ uint8_t *buf = pData; ++ uint32_t buf_size = iSize; ++ uint8_t unit_type; ++ int32_t nal_size; ++ uint32_t cumul_size = 0; ++ const uint8_t *buf_end = buf + buf_size; ++ ++ do ++ { ++ if (buf + m_sps_pps_context.length_size > buf_end) ++ goto fail; ++ ++ if (m_sps_pps_context.length_size == 1) ++ nal_size = buf[0]; ++ else if (m_sps_pps_context.length_size == 2) ++ nal_size = buf[0] << 8 | buf[1]; ++ else ++ nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; ++ ++ // FIXME CLog::Log(LOGERROR, "%s - nal_size : %d \n", __FUNCTION__, nal_size); ++ buf += m_sps_pps_context.length_size; ++ unit_type = *buf & 0x1f; ++ ++ if (buf + nal_size > buf_end || nal_size < 0) ++ goto fail; ++ ++ // prepend only to the first type 5 NAL unit of an IDR picture ++ if (m_sps_pps_context.first_idr && unit_type == 5) ++ { ++ bitstream_alloc_and_copy(poutbuf, poutbuf_size, ++ m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size); ++ m_sps_pps_context.first_idr = 0; ++ } ++ else ++ { ++ bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size); ++ if (!m_sps_pps_context.first_idr && unit_type == 1) ++ m_sps_pps_context.first_idr = 1; ++ } ++ ++ buf += nal_size; ++ cumul_size += nal_size + m_sps_pps_context.length_size; ++ } while (cumul_size < buf_size); ++ ++ return true; ++ ++fail: ++ free(*poutbuf); ++ *poutbuf = NULL; ++ *poutbuf_size = 0; ++ return false; ++} ++ ++void CDVDVideoCodecIMX::bitstream_alloc_and_copy( ++ uint8_t **poutbuf, int *poutbuf_size, ++ const uint8_t *sps_pps, uint32_t sps_pps_size, ++ const uint8_t *in, uint32_t in_size) ++{ ++ // based on h264_mp4toannexb_bsf.c (ffmpeg) ++ // which is Copyright (c) 2007 Benoit Fouet ++ // and Licensed GPL 2.1 or greater ++ ++ #define CHD_WB32(p, d) { \ ++ ((uint8_t*)(p))[3] = (d); \ ++ ((uint8_t*)(p))[2] = (d) >> 8; \ ++ ((uint8_t*)(p))[1] = (d) >> 16; \ ++ ((uint8_t*)(p))[0] = (d) >> 24; } ++ ++ uint32_t offset = *poutbuf_size; ++ uint8_t nal_header_size = offset ? 3 : 4; ++ ++ *poutbuf_size += sps_pps_size + in_size + nal_header_size; ++ *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size); ++ if (sps_pps) ++ memcpy(*poutbuf + offset, sps_pps, sps_pps_size); ++ ++ memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); ++ if (!offset) ++ { ++ CHD_WB32(*poutbuf + sps_pps_size, 1); ++ } ++ else ++ { ++ (*poutbuf + offset + sps_pps_size)[0] = 0; ++ (*poutbuf + offset + sps_pps_size)[1] = 0; ++ (*poutbuf + offset + sps_pps_size)[2] = 1; ++ } ++} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +new file mode 100644 +index 0000000..d72b899 +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -0,0 +1,191 @@ ++#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 ++ * . ++ * ++ */ ++#include ++#include ++#include ++#include "DVDVideoCodec.h" ++#include "DVDStreamInfo.h" ++#include "threads/CriticalSection.h" ++ ++ ++//#define IMX_PROFILE ++ ++/* FIXME TODO Develop real proper CVPUBuffer class */ ++#define VPU_DEC_MAX_NUM_MEM_NUM 20 ++typedef struct ++{ ++ //virtual mem info ++ int nVirtNum; ++ unsigned int virtMem[VPU_DEC_MAX_NUM_MEM_NUM]; ++ ++ //phy mem info ++ int nPhyNum; ++ unsigned int phyMem_virtAddr[VPU_DEC_MAX_NUM_MEM_NUM]; ++ unsigned int phyMem_phyAddr[VPU_DEC_MAX_NUM_MEM_NUM]; ++ unsigned int phyMem_cpuAddr[VPU_DEC_MAX_NUM_MEM_NUM]; ++ unsigned int phyMem_size[VPU_DEC_MAX_NUM_MEM_NUM]; ++} DecMemInfo; ++ ++/* Output frame properties */ ++struct CIMXOutputFrame { ++ // Render a picture. Calls RenderingFrames.Queue ++ void Render(struct v4l2_crop &); ++ // Clear a picture by settings the frameNo to "expired" ++ void Release() { frameNo = 0; } ++ ++ int v4l2BufferIdx; ++ VpuFieldType field; ++ VpuRect picCrop; ++ unsigned int nQ16ShiftWidthDivHeightRatio; ++ int frameNo; ++#ifdef IMX_PROFILE ++ unsigned long long pushTS; ++#endif ++}; ++ ++class CIMXRenderingFrames ++{ ++public: ++ static CIMXRenderingFrames& GetInstance(); ++ bool AllocateBuffers(const struct v4l2_format *, int); ++ void *GetVirtAddr(int idx); ++ void *GetPhyAddr(int idx); ++ void ReleaseBuffers(); ++ int FindBuffer(void *); ++ int DeQueue(bool wait); ++ void Queue(CIMXOutputFrame *, struct v4l2_crop &); ++ ++private: ++ CIMXRenderingFrames(); ++ void __ReleaseBuffers(); ++ ++ static const char *m_v4lDeviceName; // V4L2 device Name ++ static CIMXRenderingFrames* m_instance; // Unique instance of the class ++ ++ CCriticalSection m_renderingFramesLock; // Lock to ensure multithreading safety for class fields ++ bool m_ready; // Buffers are allocated and frames can be Queued/Dequeue ++ int m_v4lfd; // fd on V4L2 device ++ struct v4l2_buffer *m_v4lBuffers; // Table of V4L buffer info (as returned by VIDIOC_QUERYBUF) ++ int m_bufferNum; // Number of allocated V4L2 buffers ++ struct v4l2_crop m_crop; // Current cropping properties ++ bool m_streamOn; // Flag that indicates whether streaming in on (from V4L point of view) ++ int m_pushedFrames; // Number of frames queued in V4L2 ++ void **m_virtAddr; // Table holding virtual adresses of mmaped V4L2 buffers ++ int m_motionCtrl; // Current motion control algo ++}; ++ ++class CDVDVideoCodecIMX : public CDVDVideoCodec ++{ ++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 GetPicture(DVDVideoPicture *pDvdVideoPicture); ++ virtual void SetDropState(bool bDrop); ++ virtual const char* GetName(void) { return (const char*)m_pFormatName; } ++ virtual unsigned GetAllowedReferences(); ++ ++protected: ++ ++ bool VpuOpen(void); ++ bool VpuAllocBuffers(VpuMemInfo *); ++ bool VpuFreeBuffers(void); ++ bool VpuAllocFrameBuffers(void); ++ bool VpuPushFrame(VpuDecOutFrameInfo*); ++ bool VpuDeQueueFrame(bool); ++ int GetAvailableBufferNb(void); ++ void InitFB(void); ++ void RestoreFB(void); ++ void FlushDecodedFrames(void); ++ bool VpuReleaseBufferV4L(int); ++ ++ /* Helper structure which holds a queued output frame ++ * and its associated decoder frame buffer.*/ ++ struct VpuV4LFrameBuffer ++ { ++ // Returns whether the buffer is currently used (associated) ++ bool used() const { return buffer != NULL; } ++ int frameNo() const { return outputFrame.frameNo; } ++ bool expired(int frameNo) const ++ { return (buffer != NULL) && (outputFrame.frameNo < frameNo); } ++ // Associate a VPU frame buffer ++ void store(VpuFrameBuffer *b, int frameNo) { ++ buffer = b; ++ outputFrame.frameNo = frameNo; ++ } ++ // Reset the state ++ void clear() { store(NULL, 0); } ++ ++ VpuFrameBuffer *buffer; ++ CIMXOutputFrame outputFrame; ++ }; ++ ++ static const int m_extraVpuBuffers; // Number of additional buffers for VPU ++ ++ CIMXRenderingFrames&m_renderingFrames; // The global RenderingFrames instance ++ 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 ++ DecMemInfo 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 ++ void *m_tsm; // fsl Timestamp manager (from gstreamer implementation) ++ bool m_tsSyncRequired; // state whether timestamp manager has to be sync'ed ++ bool m_dropState; // Current drop state ++ int m_vpuFrameBufferNum; // Total number of allocated frame buffers ++ VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description ++ VpuMemDesc *m_extraMem; // Table of allocated extra Memory ++ VpuV4LFrameBuffer *m_outputBuffers; // Table of V4L buffers out of VPU (index is V4L buf index) (used to call properly VPU_DecOutFrameDisplayed) ++ std::queue m_decodedFrames; // Decoded Frames ready to be retrieved by GetPicture ++ int m_frameCounter; // Decoded frames counter ++ bool m_usePTS; // State whether pts out of decoding process should be used ++ ++ /* FIXME : Rework is still required for fields below this line */ ++ ++ /* create a real class and share with openmax ? */ ++ // bitstream to bytestream (Annex B) conversion support. ++ bool bitstream_convert_init(void *in_extradata, int in_extrasize); ++ bool bitstream_convert(BYTE* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size); ++ static void bitstream_alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size, ++ const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size); ++ typedef struct omx_bitstream_ctx { ++ uint8_t length_size; ++ uint8_t first_idr; ++ uint8_t *sps_pps_data; ++ uint32_t size; ++ omx_bitstream_ctx() ++ { ++ length_size = 0; ++ first_idr = 0; ++ sps_pps_data = NULL; ++ size = 0; ++ } ++ } omx_bitstream_ctx; ++ uint32_t m_sps_pps_size; ++ omx_bitstream_ctx m_sps_pps_context; ++ bool m_convert_bitstream; ++ ++}; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +index 8a97889..1df37c6 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +@@ -24,6 +24,9 @@ SRCS += OpenMax.cpp + SRCS += OpenMaxVideo.cpp + SRCS += DVDVideoCodecOpenMax.cpp + endif ++ifeq (@USE_IMXVPU@,1) ++SRCS += DVDVideoCodecIMX.cpp mfw_gst_ts.c ++endif + ifeq (@USE_LIBAMCODEC@,1) + SRCS += AMLCodec.cpp + SRCS += DVDVideoCodecAmlogic.cpp +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c b/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c +new file mode 100644 +index 0000000..86a8fea +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c +@@ -0,0 +1,752 @@ ++/* ++ * Copyright (c) 2010-2012, Freescale Semiconductor, Inc. All rights reserved. ++ * ++ */ ++ ++/* ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Module Name: TimeStamp.c ++ * ++ * Description: include TimeStamp stratege for VPU / SW video decoder plugin ++ * ++ * Portability: This code is written for Linux OS and Gstreamer ++ */ ++ ++/* ++ * Changelog: ++ 11/2/2010 draft version Lyon Wang ++ * ++ */ ++#include ++#include ++#include ++ ++#include "mfw_gst_ts.h" ++ ++ ++const char *debug_env = "ME_DEBUG"; ++char *debug = NULL; ++int debug_level = 0; ++ ++ ++enum ++{ ++ DEBUG_LEVEL_ERROR = 1, ++ DEBUG_LEVEL_WARNING, ++ DEBUG_LEVEL_LOG, ++ DEBUG_LEVEL_VERBOSE, ++}; ++ ++ ++#define TSM_MESSAGE(level, fmt, ...)\ ++ do{\ ++ if (debug_level>=(level)){\ ++ printf("TSM:"fmt, ##__VA_ARGS__);\ ++ }\ ++ }while(0) ++ ++#define TSM_ERROR(...) TSM_MESSAGE(DEBUG_LEVEL_ERROR, ##__VA_ARGS__) ++#define TSM_WARNING(...) TSM_MESSAGE(DEBUG_LEVEL_WARNING, ##__VA_ARGS__) ++#define TSM_LOG(...) TSM_MESSAGE(DEBUG_LEVEL_LOG, ##__VA_ARGS__) ++#define TSM_VERBOSE(...) TSM_MESSAGE(DEBUG_LEVEL_VERBOSE, ##__VA_ARGS__) ++ ++#define TSM_HISTORY_POWER 5 ++#define TSM_HISTORY_SIZE (1<dur_history_total>>TSM_HISTORY_POWER) ++ ++#define TSM_SECOND ((TSM_TIMESTAMP)1000000000) ++#define TSM_DEFAULT_INTERVAL (TSM_SECOND/30) ++#define TSM_DEFAULT_TS_BUFFER_SIZE (128) ++ ++#define TSM_TS_IS_VALID(ts) \ ++ ((ts) != TSM_TIMESTAMP_NONE) ++ ++#define TSM_KEY_IS_VALID(key) \ ++ ((key) != TSM_KEY_NONE) ++ ++#define TSM_DISTANCE(tsm)\ ++ (((tsm->rx)>=(tsm->tx))?((tsm->rx)-(tsm->tx)):(tsm->ts_buf_size-(tsm->tx)+(tsm->rx))) ++ ++#define TSM_PLUS_AGE(tsm)\ ++ (TSM_DISTANCE(tsm)+tsm->invalid_ts_count+2) ++ ++#define TSM_ABS(ts0, ts1)\ ++ (((ts0)>(ts1))?((ts0)-(ts1)):((ts1)-(ts0))) ++ ++#define TSM_TIME_FORMAT "u:%02u:%02u.%09u" ++ ++#define TSM_TIME_ARGS(t) \ ++ TSM_TS_IS_VALID (t) ? \ ++ (unsigned int) (((TSM_TIMESTAMP)(t)) / (TSM_SECOND * 60 * 60)) : 99, \ ++ TSM_TS_IS_VALID (t) ? \ ++ (unsigned int) ((((TSM_TIMESTAMP)(t)) / (TSM_SECOND * 60)) % 60) : 99, \ ++ TSM_TS_IS_VALID (t) ? \ ++ (unsigned int) ((((TSM_TIMESTAMP)(t)) / TSM_SECOND) % 60) : 99, \ ++ TSM_TS_IS_VALID (t) ? \ ++ (unsigned int) (((TSM_TIMESTAMP)(t)) % TSM_SECOND) : 999999999 ++ ++#define TSM_BUFFER_SET(buf, value, size) \ ++ do {\ ++ int i;\ ++ for (i=0;i<(size);i++){\ ++ (buf)[i] = (value);\ ++ }\ ++ }while(0) ++ ++#define TSM_RECEIVED_NUNBER 512 ++ ++ ++typedef struct ++{ ++ TSM_TIMESTAMP ts; ++ unsigned long long age; ++ void *key; ++} TSMControl; ++ ++typedef struct _TSMReceivedEntry ++{ ++ TSM_TIMESTAMP ts; ++ struct _TSMReceivedEntry *next; ++ unsigned int used:1; ++ unsigned int subentry:1; ++ int size; ++} TSMReceivedEntry; ++ ++typedef struct _TSMReceivedEntryMemory ++{ ++ struct _TSMReceivedEntryMemory *next; ++ TSMReceivedEntry entrys[TSM_RECEIVED_NUNBER]; ++} TSMReceivedEntryMemory; ++ ++typedef struct ++{ ++ TSMReceivedEntry *head; ++ TSMReceivedEntry *tail; ++ TSMReceivedEntry *free; ++ TSMReceivedEntryMemory *memory; ++ int cnt; ++} TSMRecivedCtl; ++ ++typedef struct _TSManager ++{ ++ int first_tx; ++ int first_rx; ++ int rx; //timestamps received ++ int tx; //timestamps transfered ++ TSM_TIMESTAMP last_ts_sent; //last time stamp sent ++ TSM_TIMESTAMP last_ts_received; ++ TSM_TIMESTAMP suspicious_ts; ++ ++ TSM_TIMESTAMP discont_threshold; ++ ++ unsigned int invalid_ts_count; ++ TSMGR_MODE mode; ++ int ts_buf_size; ++ int dur_history_tx; ++ TSM_TIMESTAMP dur_history_total; ++ TSM_TIMESTAMP dur_history_buf[TSM_HISTORY_SIZE]; ++ TSMControl *ts_buf; ++ unsigned long long age; ++ int tx_cnt; ++ int rx_cnt; ++ int cnt; ++ int valid_ts_received:1; ++ int big_cnt; ++ ++ TSMRecivedCtl rctl; ++} TSManager; ++ ++ ++static void ++tsm_free_received_entry (TSMRecivedCtl * rctl, TSMReceivedEntry * entry) ++{ ++ entry->next = rctl->free; ++ rctl->free = entry; ++} ++ ++ ++static TSMReceivedEntry * ++tsm_new_received_entry (TSMRecivedCtl * rctl) ++{ ++ TSMReceivedEntry *ret = NULL; ++ if (rctl->free) { ++ ret = rctl->free; ++ rctl->free = ret->next; ++ } else { ++ TSMReceivedEntryMemory *p = malloc (sizeof (TSMReceivedEntryMemory)); ++ if (p) { ++ int i; ++ for (i = 1; i < TSM_RECEIVED_NUNBER; i++) { ++ TSMReceivedEntry *e = &p->entrys[i]; ++ tsm_free_received_entry (rctl, e); ++ }; ++ ++ p->next = rctl->memory; ++ rctl->memory = p; ++ ++ ret = p->entrys; ++ } ++ } ++ return ret; ++} ++ ++ ++void ++TSManagerReceive2 (void *handle, TSM_TIMESTAMP timestamp, int size) ++{ ++#define CLEAR_TSM_RENTRY(entry)\ ++ do { \ ++ (entry)->used = 0; \ ++ (entry)->subentry = 0; \ ++ (entry)->next = NULL; \ ++ } while (0) ++ TSManager *tsm = (TSManager *) handle; ++ ++ TSM_VERBOSE ("receive2 %" TSM_TIME_FORMAT " size %d\n", ++ TSM_TIME_ARGS (timestamp), size); ++ ++ if (tsm) { ++ if (size > 0) { ++ TSMRecivedCtl *rctl = &tsm->rctl; ++ TSMReceivedEntry *e = tsm_new_received_entry (rctl); ++ if (e) { ++ CLEAR_TSM_RENTRY (e); ++ if ((rctl->tail) && (rctl->tail->ts == timestamp)) { ++ e->subentry = 1; ++ } ++ e->ts = timestamp; ++ e->size = size; ++ if (rctl->tail) { ++ rctl->tail->next = e; ++ rctl->tail = e; ++ } else { ++ rctl->head = rctl->tail = e; ++ } ++ } ++ rctl->cnt++; ++ } else { ++ TSManagerReceive (handle, timestamp); ++ } ++ } ++} ++ ++ ++static TSM_TIMESTAMP ++TSManagerGetLastTimeStamp (TSMRecivedCtl * rctl, int size, int use) ++{ ++ TSM_TIMESTAMP ts = TSM_TIMESTAMP_NONE; ++ TSMReceivedEntry *e; ++ while ((size > 0) && (e = rctl->head)) { ++ ts = ((e->used) ? (TSM_TIMESTAMP_NONE) : (e->ts)); ++ if (use) ++ e->used = 1; ++ if (size >= e->size) { ++ rctl->head = e->next; ++ if (rctl->head == NULL) { ++ rctl->tail = NULL; ++ } else { ++ if (rctl->head->subentry) { ++ rctl->head->used = e->used; ++ } ++ } ++ size -= e->size; ++ rctl->cnt--; ++ tsm_free_received_entry (rctl, e); ++ } else { ++ e->size -= size; ++ size = 0; ++ } ++ } ++ return ts; ++} ++ ++ ++void ++TSManagerFlush2 (void *handle, int size) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ if (tsm) { ++ TSManagerGetLastTimeStamp (&tsm->rctl, size, 0); ++ } ++ ++} ++ ++ ++/*====================================================================================== ++FUNCTION: mfw_gst_receive_ts ++ ++DESCRIPTION: Check timestamp and do frame dropping if enabled ++ ++ARGUMENTS PASSED: pTimeStamp_Object - TimeStamp Manager to handle related timestamp ++ timestamp - time stamp of the input buffer which has video data. ++ ++RETURN VALUE: None ++PRE-CONDITIONS: None ++POST-CONDITIONS: None ++IMPORTANT NOTES: None ++=======================================================================================*/ ++static void ++_TSManagerReceive (void *handle, TSM_TIMESTAMP timestamp, void *key) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ ++ if (tsm) { ++ if (TSM_TS_IS_VALID (timestamp) && (tsm->rx_cnt)) ++ tsm->valid_ts_received = 1; ++ tsm->rx_cnt++; ++ if (tsm->cnt < tsm->ts_buf_size - 1) { ++ tsm->cnt++; ++ if (tsm->mode == MODE_AI) { ++ ++ if (TSM_TS_IS_VALID (timestamp)) { ++ if (tsm->first_rx) { ++ tsm->last_ts_received = timestamp; ++ tsm->first_rx = 0; ++ } else { ++ if (tsm->suspicious_ts) { ++ if (timestamp >= tsm->suspicious_ts) { ++ tsm->last_ts_received = timestamp; ++ } ++ tsm->suspicious_ts = 0; ++ } ++ if ((timestamp > tsm->last_ts_received) ++ && (timestamp - tsm->last_ts_received > tsm->discont_threshold)) { ++ tsm->suspicious_ts = timestamp; ++ timestamp = TSM_TIMESTAMP_NONE; ++ } ++ } ++ } ++ ++ if (TSM_TS_IS_VALID (timestamp)) // && (TSM_ABS(timestamp, tsm->last_ts_sent)ts_buf[tsm->rx].ts = timestamp; ++ tsm->ts_buf[tsm->rx].age = tsm->age + TSM_PLUS_AGE (tsm); ++ tsm->ts_buf[tsm->rx].key = key; ++ tsm->last_ts_received = timestamp; ++#ifdef DEBUG ++ //printf("age should %lld %lld\n", tsm->age, tsm->ts_buf[tsm->rx].age); ++ //printf("++++++ distance = %d tx=%d, rx=%d, invalid count=%d\n", TSM_DISTANCE(tsm), tsm->tx, tsm->rx,tsm->invalid_ts_count); ++#endif ++ tsm->rx = ((tsm->rx + 1) % tsm->ts_buf_size); ++ } else { ++ tsm->invalid_ts_count++; ++ } ++ } else if (tsm->mode == MODE_FIFO) { ++ tsm->ts_buf[tsm->rx].ts = timestamp; ++ tsm->rx = ((tsm->rx + 1) % tsm->ts_buf_size); ++ } ++ TSM_LOG ("++Receive %d:%" TSM_TIME_FORMAT ++ ", invalid:%d, size:%d key %p\n", tsm->rx_cnt, ++ TSM_TIME_ARGS (timestamp), tsm->invalid_ts_count, tsm->cnt, key); ++ } else { ++ TSM_ERROR ("Too many timestamps recieved!! (cnt=%d)\n", tsm->cnt); ++ } ++ } ++} ++ ++ ++void ++TSManagerValid2 (void *handle, int size, void *key) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ ++ TSM_VERBOSE ("valid2 size %d\n", size); ++ ++ if (tsm) { ++ TSM_TIMESTAMP ts; ++ ts = TSManagerGetLastTimeStamp (&tsm->rctl, size, 1); ++ _TSManagerReceive (tsm, ts, key); ++ } ++} ++ ++ ++void ++TSManagerReceive (void *handle, TSM_TIMESTAMP timestamp) ++{ ++ _TSManagerReceive (handle, timestamp, TSM_KEY_NONE); ++} ++ ++ ++/*====================================================================================== ++FUNCTION: TSManagerSend ++ ++DESCRIPTION: Check timestamp and do frame dropping if enabled ++ ++ARGUMENTS PASSED: pTimeStamp_Object - TimeStamp Manager to handle related timestamp ++ ptimestamp - returned timestamp to use at render ++ ++RETURN VALUE: None ++PRE-CONDITIONS: None ++POST-CONDITIONS: None ++IMPORTANT NOTES: None ++=======================================================================================*/ ++static TSM_TIMESTAMP ++_TSManagerSend2 (void *handle, void *key, int send) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ int i = tsm->tx; ++ int index = -1; ++ TSM_TIMESTAMP ts0 = 0, tstmp = TSM_TIMESTAMP_NONE; ++ unsigned long long age = 0; ++ TSM_TIMESTAMP half_interval = TSM_ADAPTIVE_INTERVAL (tsm) >> 1; ++ ++ if (tsm) { ++ if (send) { ++ tsm->tx_cnt++; ++ } else { ++ tsm->cnt++; ++ tsm->invalid_ts_count++; ++ } ++ if (tsm->cnt > 0) { ++ if (send) { ++ tsm->cnt--; ++ } ++ if (tsm->mode == MODE_AI) { ++ ++ if (tsm->first_tx == 0) { ++ tstmp = tsm->last_ts_sent + TSM_ADAPTIVE_INTERVAL (tsm); ++ } else { ++ tstmp = tsm->last_ts_sent; ++ } ++ ++ while (i != tsm->rx) { ++ if (index >= 0) { ++ if (tsm->ts_buf[i].ts < ts0) { ++ ts0 = tsm->ts_buf[i].ts; ++ age = tsm->ts_buf[i].age; ++ index = i; ++ } ++ } else { ++ ts0 = tsm->ts_buf[i].ts; ++ age = tsm->ts_buf[i].age; ++ index = i; ++ } ++ if ((TSM_KEY_IS_VALID (key)) && (key == tsm->ts_buf[i].key)) ++ break; ++ i = ((i + 1) % tsm->ts_buf_size); ++ } ++ if (index >= 0) { ++ if ((tsm->invalid_ts_count) && (ts0 >= ((tstmp) + half_interval)) ++ && (age > tsm->age)) { ++ /* use calculated ts0 */ ++ if (send) { ++ tsm->invalid_ts_count--; ++ } ++ } else { ++ ++ if (send) { ++ if (index != tsm->tx) { ++ tsm->ts_buf[index] = tsm->ts_buf[tsm->tx]; ++ } ++ tsm->tx = ((tsm->tx + 1) % tsm->ts_buf_size); ++ ++ } ++#if 0 ++ if (ts0 >= ((tstmp) + half_interval)) ++ tstmp = tstmp; ++ else ++ tstmp = ts0; ++#else ++ tstmp = ts0; ++#endif ++ } ++ ++ } else { ++ if (send) { ++ tsm->invalid_ts_count--; ++ } ++ } ++ ++ if (tsm->first_tx == 0) { ++ ++ if (tstmp > tsm->last_ts_sent) { ++ ts0 = (tstmp - tsm->last_ts_sent); ++ } else { ++ ts0 = 0; ++ tstmp = tsm->last_ts_sent; ++ } ++ ++ if (ts0 > TSM_ADAPTIVE_INTERVAL (tsm) * 3 / 2) { ++ TSM_WARNING ("Jitter1:%" TSM_TIME_FORMAT " %" TSM_TIME_FORMAT "\n", ++ TSM_TIME_ARGS (ts0), ++ TSM_TIME_ARGS (TSM_ADAPTIVE_INTERVAL (tsm) * 3 / 2)); ++ } else if (ts0 == 0) { ++ TSM_WARNING ("Jitter:%" TSM_TIME_FORMAT "\n", TSM_TIME_ARGS (ts0)); ++ } ++ ++ if (send) { ++ if ((ts0 < TSM_ADAPTIVE_INTERVAL (tsm) * 2) || (tsm->big_cnt > 3)) { ++ tsm->big_cnt = 0; ++ tsm->dur_history_total -= ++ tsm->dur_history_buf[tsm->dur_history_tx]; ++ tsm->dur_history_buf[tsm->dur_history_tx] = ts0; ++ tsm->dur_history_tx = ++ ((tsm->dur_history_tx + 1) % TSM_HISTORY_SIZE); ++ tsm->dur_history_total += ts0; ++ } else { ++ tsm->big_cnt++; ++ } ++ } ++ } ++ ++ if (send) { ++ tsm->last_ts_sent = tstmp; ++ tsm->age++; ++ tsm->first_tx = 0; ++ } ++ ++ } else if (tsm->mode == MODE_FIFO) { ++ tstmp = tsm->ts_buf[tsm->tx].ts; ++ if (send) { ++ tsm->tx = ((tsm->tx + 1) % tsm->ts_buf_size); ++ } ++ ts0 = tstmp - tsm->last_ts_sent; ++ if (send) { ++ tsm->last_ts_sent = tstmp; ++ } ++ } ++ ++ if (send) { ++ TSM_LOG ("--Send %d:%" TSM_TIME_FORMAT ", int:%" TSM_TIME_FORMAT ++ ", avg:%" TSM_TIME_FORMAT " inkey %p\n", tsm->tx_cnt, ++ TSM_TIME_ARGS (tstmp), TSM_TIME_ARGS (ts0), ++ TSM_TIME_ARGS (TSM_ADAPTIVE_INTERVAL (tsm)), key); ++ } ++ ++ } else { ++ if (tsm->valid_ts_received == 0) { ++ if (tsm->first_tx) { ++ tstmp = tsm->last_ts_sent; ++ } else { ++ tstmp = tsm->last_ts_sent + TSM_ADAPTIVE_INTERVAL (tsm); ++ } ++ if (send) { ++ tsm->first_tx = 0; ++ tsm->last_ts_sent = tstmp; ++ } ++ } ++ TSM_ERROR ("Too many timestamps send!!\n"); ++ } ++ ++ if (send == 0) { ++ tsm->cnt--; ++ tsm->invalid_ts_count--; ++ } ++ ++ } ++ ++ return tstmp; ++} ++ ++ ++TSM_TIMESTAMP ++TSManagerSend2 (void *handle, void *key) ++{ ++ return _TSManagerSend2 (handle, key, 1); ++} ++ ++ ++TSM_TIMESTAMP ++TSManagerQuery2 (void *handle, void *key) ++{ ++ return _TSManagerSend2 (handle, key, 0); ++} ++ ++ ++TSM_TIMESTAMP ++TSManagerSend (void *handle) ++{ ++ return TSManagerSend2 (handle, TSM_KEY_NONE); ++} ++ ++ ++TSM_TIMESTAMP ++TSManagerQuery (void *handle) ++{ ++ return TSManagerQuery2 (handle, TSM_KEY_NONE); ++} ++ ++ ++void ++resyncTSManager (void *handle, TSM_TIMESTAMP synctime, TSMGR_MODE mode) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ if (tsm) { ++ TSMRecivedCtl *rctl = &tsm->rctl; ++ TSMReceivedEntry *e = rctl->head; ++ ++ while ((e = rctl->head)) { ++ rctl->head = e->next; ++ tsm_free_received_entry (rctl, e); ++ }; ++ rctl->cnt = 0; ++ ++ rctl->tail = NULL; ++ ++ tsm->first_tx = 1; ++ tsm->first_rx = 1; ++ tsm->suspicious_ts = 0; ++ ++ if (TSM_TS_IS_VALID (synctime)) ++ tsm->last_ts_sent = synctime; ++ ++ tsm->tx = tsm->rx = 0; ++ tsm->invalid_ts_count = 0; ++ tsm->mode = mode; ++ tsm->age = 0; ++ tsm->rx_cnt = tsm->tx_cnt = tsm->cnt = 0; ++ tsm->valid_ts_received = 0; ++ ++ tsm->big_cnt = 0; ++ } ++} ++ ++ ++/*====================================================================================== ++FUNCTION: mfw_gst_init_ts ++ ++DESCRIPTION: malloc and initialize timestamp strcture ++ ++ARGUMENTS PASSED: ppTimeStamp_Object - pointer of TimeStamp Manager to handle related timestamp ++ ++RETURN VALUE: TimeStamp structure pointer ++PRE-CONDITIONS: None ++POST-CONDITIONS: None ++IMPORTANT NOTES: None ++=======================================================================================*/ ++void * ++createTSManager (int ts_buf_size) ++{ ++ TSManager *tsm = (TSManager *) malloc (sizeof (TSManager)); ++ debug = getenv (debug_env); ++ if (debug) { ++ debug_level = atoi (debug); ++ } ++ // printf("debug = %s \n ++++++++++++++++++++++++++++",debug); ++ if (tsm) { ++ memset (tsm, 0, sizeof (TSManager)); ++ if (ts_buf_size <= 0) { ++ ts_buf_size = TSM_DEFAULT_TS_BUFFER_SIZE; ++ } ++ tsm->ts_buf_size = ts_buf_size; ++ tsm->ts_buf = malloc (sizeof (TSMControl) * ts_buf_size); ++ ++ if (tsm->ts_buf == NULL) { ++ goto fail; ++ } ++ ++ resyncTSManager (tsm, (TSM_TIMESTAMP) 0, MODE_AI); ++ ++ tsm->dur_history_tx = 0; ++ TSM_BUFFER_SET (tsm->dur_history_buf, TSM_DEFAULT_INTERVAL, ++ TSM_HISTORY_SIZE); ++ tsm->dur_history_total = TSM_DEFAULT_INTERVAL << TSM_HISTORY_POWER; ++ ++ tsm->discont_threshold = 10000000000LL; // 10s ++ } ++ return tsm; ++fail: ++ if (tsm) { ++ if (tsm->ts_buf) { ++ free (tsm->ts_buf); ++ } ++ free (tsm); ++ tsm = NULL; ++ } ++ return tsm; ++} ++ ++ ++void ++destroyTSManager (void *handle) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ if (tsm) { ++ TSMRecivedCtl *rctl = &tsm->rctl; ++ TSMReceivedEntryMemory *rmem; ++ if (tsm->ts_buf) { ++ free (tsm->ts_buf); ++ } ++ ++ while ((rmem = rctl->memory)) { ++ rctl->memory = rmem->next; ++ free (rmem); ++ } ++ free (tsm); ++ tsm = NULL; ++ } ++} ++ ++ ++void ++setTSManagerFrameRate (void *handle, int fps_n, int fps_d) ++//void setTSManagerFrameRate(void * handle, float framerate) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ TSM_TIMESTAMP ts; ++ if ((fps_n > 0) && (fps_d > 0) && (fps_n / fps_d <= 80)) ++ ts = TSM_SECOND * fps_d / fps_n; ++ else ++ ts = TSM_DEFAULT_INTERVAL; ++ // TSM_TIMESTAMP ts = TSM_SECOND / framerate; ++ ++ if (tsm) { ++ TSM_BUFFER_SET (tsm->dur_history_buf, ts, TSM_HISTORY_SIZE); ++ tsm->dur_history_total = (ts << TSM_HISTORY_POWER); ++ if (debug) ++ TSM_LOG ("Set frame intrval:%" TSM_TIME_FORMAT "\n", TSM_TIME_ARGS (ts)); ++ } ++} ++ ++ ++TSM_TIMESTAMP ++getTSManagerFrameInterval (void *handle) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ TSM_TIMESTAMP ts = 0; ++ if (tsm) { ++ ts = TSM_ADAPTIVE_INTERVAL (tsm); ++ } ++ return ts; ++} ++ ++ ++TSM_TIMESTAMP ++getTSManagerPosition (void *handle) ++{ ++ TSManager *tsm = (TSManager *) handle; ++ TSM_TIMESTAMP ts = 0; ++ if (tsm) { ++ ts = tsm->last_ts_sent; ++ } ++ return ts; ++} ++ ++ ++int ++getTSManagerPreBufferCnt (void *handle) ++{ ++ int i = 0; ++ TSManager *tsm = (TSManager *) handle; ++ if (tsm) { ++ i = tsm->rctl.cnt; ++ } ++ return i; ++} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h +new file mode 100644 +index 0000000..f5d66c4 +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (c) 2010-2012, Freescale Semiconductor, Inc. All rights reserved. ++ * ++ */ ++ ++/* ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ */ ++ ++/* ++ * Module Name: TimeStamp.h ++ * ++ * Description: include TimeStamp stratege for VPU / SW video decoder plugin ++ * ++ * Portability: This code is written for Linux OS and Gstreamer ++ */ ++ ++/* ++ * Changelog: ++ 11/2/2010 draft version Lyon Wang ++ * ++ */ ++ ++#ifndef _TIMESTAMP_H_ ++#define _TIMESTAMP_H_ ++ ++ ++/** ++ * GST_CLOCK_TIME_NONE: ++ * ++ * Constant to define an undefined clock time. ++ */ ++ ++typedef long long TSM_TIMESTAMP; ++ ++typedef enum ++{ ++ MODE_AI, ++ MODE_FIFO, ++} TSMGR_MODE; ++ ++#define TSM_TIMESTAMP_NONE ((long long)(-1)) ++#define TSM_KEY_NONE ((void *)0) ++ ++/** ++ * GST_CLOCK_TIME_IS_VALID: ++ * @time: clock time to validate ++ * ++ * Tests if a given #GstClockTime represents a valid defined time. ++ */ ++ ++#ifdef __cplusplus ++#define EXTERN ++#else ++#define EXTERN extern ++#endif ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++/*! ++ * This function receive timestamp into timestamp manager. ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @param timestamp timestamp received ++ * ++ * @return ++ */ ++ EXTERN void TSManagerReceive (void *handle, TSM_TIMESTAMP timestamp); ++ ++ EXTERN void TSManagerReceive2 (void *handle, TSM_TIMESTAMP timestamp, ++ int size); ++ ++ EXTERN void TSManagerFlush2 (void *handle, int size); ++ ++ EXTERN void TSManagerValid2 (void *handle, int size, void *key); ++ ++/*! ++ * This function send the timestamp for next output frame. ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @return timestamp for next output frame. ++ */ ++ EXTERN TSM_TIMESTAMP TSManagerSend (void *handle); ++ ++ EXTERN TSM_TIMESTAMP TSManagerSend2 (void *handle, void *key); ++ ++ EXTERN TSM_TIMESTAMP TSManagerQuery2 (void *handle, void *key); ++ ++ EXTERN TSM_TIMESTAMP TSManagerQuery (void *handle); ++/*! ++ * This function resync timestamp handler when reset and seek ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @param synctime the postion time needed to set, if value invalid, position keeps original ++ * ++ * @param mode playing mode (AI or FIFO) ++ * ++ * @return ++ */ ++ EXTERN void resyncTSManager (void *handle, TSM_TIMESTAMP synctime, ++ TSMGR_MODE mode); ++/*! ++ * This function create and reset timestamp handler ++ * ++ * @param ts_buf_size time stamp queue buffer size ++ * ++ * @return ++ */ ++ EXTERN void *createTSManager (int ts_buf_size); ++/*! ++ * This function destory timestamp handler ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @return ++ */ ++ EXTERN void destroyTSManager (void *handle); ++/*! ++ * This function set history buffer frame interval by fps_n and fps_d ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @param framerate the framerate to be set ++ * ++ * @return ++ */ ++ EXTERN void setTSManagerFrameRate (void *handle, int fps_n, int fps_d); ++//EXTERN void setTSManagerFrameRate(void * handle, float framerate); ++/*! ++ * This function set the current calculated Frame Interval ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @return ++ */ ++ EXTERN TSM_TIMESTAMP getTSManagerFrameInterval (void *handle); ++/*! ++ * This function get the current time stamp postion ++ * ++ * @param handle handle of timestamp manager. ++ * ++ * @return ++ */ ++ EXTERN TSM_TIMESTAMP getTSManagerPosition (void *handle); ++ EXTERN int getTSManagerPreBufferCnt (void *handle); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /*_TIMESTAMP_H_ */ +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 99b3155..9ce20dd 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -994,6 +994,7 @@ static std::string GetRenderFormatName(ERenderFormat format) + case RENDER_FMT_CVBREF: return "BGRA"; + case RENDER_FMT_EGLIMG: return "EGLIMG"; + case RENDER_FMT_BYPASS: return "BYPASS"; ++ case RENDER_FMT_IMX: return "IMX"; + case RENDER_FMT_MEDIACODEC:return "MEDIACODEC"; + case RENDER_FMT_NONE: return "NONE"; + } +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +new file mode 100644 +index 0000000..4ac19c4 +--- /dev/null ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -0,0 +1,272 @@ ++/* ++ * 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 ++ * . ++ * ++ */ ++ ++#include ++#include "system.h" ++#include ++ ++#include "EGLNativeTypeIMX.h" ++#include ++#include ++#include ++#include "utils/log.h" ++#include "utils/StringUtils.h" ++#include "guilib/gui3d.h" ++ ++CEGLNativeTypeIMX::CEGLNativeTypeIMX() ++{ ++} ++ ++CEGLNativeTypeIMX::~CEGLNativeTypeIMX() ++{ ++} ++ ++bool CEGLNativeTypeIMX::CheckCompatibility() ++{ ++ char name[256] = {0}; ++ get_sysfs_str("/sys/class/graphics/fb0/device/modalias", name, 255); ++ CStdString strName = name; ++ StringUtils::Trim(strName); ++ if (strName == "platform:mxc_sdc_fb") ++ return true; ++ return false; ++} ++ ++void CEGLNativeTypeIMX::Initialize() ++{ ++ struct mxcfb_gbl_alpha alpha; ++ int fd, fd2; ++ ++ ++ fd = open("/dev/fb0",O_RDWR); ++ if (fd < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); ++ return; ++ } ++ fd2 = open("/dev/fb1",O_RDWR); ++ if (fd2 < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb1.\n", __FUNCTION__); ++ return; ++ } ++ ++ /* Store screen info */ ++ if (ioctl(fd, FBIOGET_VSCREENINFO, &m_screeninfo) != 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while querying frame buffer.\n", __FUNCTION__); ++ return; ++ } ++ /* Configure overlay in the same way as BG plane */ ++ if (ioctl(fd2, FBIOPUT_VSCREENINFO, &m_screeninfo) != 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while setting overlay frame buffer.\n", __FUNCTION__); ++ return; ++ } ++ ++ /* set fb0 as the only visible layer - ioctl on /dev/fb0 so that fb0 is BG and fb1 is FG */ ++ alpha.alpha = 255; ++ alpha.enable = 1; ++ if (ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha) != 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while initializing frame buffer.\n", __FUNCTION__); ++ } ++ ++ /* Unblank the fbs */ ++ if (ioctl(fd, FBIOBLANK, 0) < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__); ++ } ++ if (ioctl(fd2, FBIOBLANK, 0) < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__); ++ } ++ ++ close(fd); ++ close(fd2); ++ ++ return; ++} ++ ++void CEGLNativeTypeIMX::Destroy() ++{ ++ struct fb_fix_screeninfo fixed_info; ++ void *fb_buffer; ++ struct mxcfb_gbl_alpha alpha; ++ int fd; ++ ++ fd = open("/dev/fb0",O_RDWR); ++ if (fd < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); ++ return; ++ } ++ /* only fb0 visible */ ++ alpha.alpha = 255; ++ alpha.enable = 1; ++ if (ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha) != 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while initializing frame buffer.\n", __FUNCTION__); ++ } ++ ++ 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); ++ ++ /* Blank overlay */ ++ fd = open("/dev/fb1",O_RDWR); ++ if (fd < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while opening /dev/fb1.\n", __FUNCTION__); ++ return; ++ } ++ if (ioctl(fd, FBIOBLANK, 1) < 0) ++ { ++ CLog::Log(LOGERROR, "%s - Error while blanking fb1.\n", __FUNCTION__); ++ } ++ close(fd); ++ ++ return; ++} ++ ++bool CEGLNativeTypeIMX::CreateNativeDisplay() ++{ ++ /* 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, m_screeninfo.xres, m_screeninfo.yres); ++ m_nativeWindow = &m_window; ++ return true; ++} ++ ++bool CEGLNativeTypeIMX::GetNativeDisplay(XBNativeDisplayType **nativeDisplay) const ++{ ++ if (!nativeDisplay) ++ return false; ++ *nativeDisplay = (XBNativeDisplayType*)m_nativeDisplay; ++ return true; ++} ++ ++bool CEGLNativeTypeIMX::GetNativeWindow(XBNativeWindowType **nativeWindow) const ++{ ++ if (!nativeWindow) ++ return false; ++ *nativeWindow = (XBNativeWindowType*)m_nativeWindow; ++ return true; ++} ++ ++bool CEGLNativeTypeIMX::DestroyNativeDisplay() ++{ ++ return true; ++} ++ ++bool CEGLNativeTypeIMX::DestroyNativeWindow() ++{ ++ return true; ++} ++ ++bool CEGLNativeTypeIMX::GetNativeResolution(RESOLUTION_INFO *res) const ++{ ++ double drate = 0, hrate = 0, vrate = 0; ++ if (!res) ++ return false; ++ ++ drate = 1e12 / m_screeninfo.pixclock; ++ hrate = drate / (m_screeninfo.left_margin + m_screeninfo.xres + m_screeninfo.right_margin + m_screeninfo.hsync_len); ++ vrate = hrate / (m_screeninfo.upper_margin + m_screeninfo.yres + m_screeninfo.lower_margin + m_screeninfo.vsync_len); ++ ++ res->iWidth = m_screeninfo.xres; ++ res->iHeight = m_screeninfo.yres; ++ res->iScreenWidth = res->iWidth; ++ res->iScreenHeight = res->iHeight; ++ res->fRefreshRate = lrint(vrate); ++ res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE; ++ 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" : ""); ++ ++ return res->iWidth > 0 && res->iHeight> 0; ++} ++ ++bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res) ++{ ++ return false; ++} ++ ++bool CEGLNativeTypeIMX::ProbeResolutions(std::vector &resolutions) ++{ ++ RESOLUTION_INFO res; ++ bool ret = false; ++ ret = GetNativeResolution(&res); ++ if (ret && res.iWidth > 1 && res.iHeight > 1) ++ { ++ resolutions.push_back(res); ++ return true; ++ } ++ return false; ++} ++ ++bool CEGLNativeTypeIMX::GetPreferredResolution(RESOLUTION_INFO *res) const ++{ ++ return false; ++} ++ ++bool CEGLNativeTypeIMX::ShowWindow(bool show) ++{ ++ // CLog::Log(LOGERROR, "%s - call CEGLNativeTypeIMX::ShowWindow with %d.\n", __FUNCTION__, show); ++ return false; ++} ++ ++int CEGLNativeTypeIMX::get_sysfs_str(const char *path, char *valstr, const int size) const ++{ ++ int fd = open(path, O_RDONLY); ++ if (fd >= 0) ++ { ++ int len = read(fd, valstr, size - 1); ++ if (len != -1 ) ++ valstr[len] = '\0'; ++ close(fd); ++ } ++ else ++ { ++ sprintf(valstr, "%s", "fail"); ++ return -1; ++ } ++ return 0; ++} +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.h b/xbmc/windowing/egl/EGLNativeTypeIMX.h +new file mode 100644 +index 0000000..61d5833 +--- /dev/null ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.h +@@ -0,0 +1,62 @@ ++#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 ++ * . ++ * ++ */ ++#include ++#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 &resolutions); ++ virtual bool GetPreferredResolution(RESOLUTION_INFO *res) const; ++ ++ virtual bool ShowWindow(bool show); ++ ++ protected: ++ int get_sysfs_str(const char *path, char *valstr, const int size) const; ++ bool ModeToResolution(const char *mode, RESOLUTION_INFO *res) const; ++ ++ EGLNativeDisplayType m_display; ++ EGLNativeWindowType m_window; ++ ++protected: ++ struct fb_var_screeninfo m_screeninfo; ++ ++}; +diff --git a/xbmc/windowing/egl/EGLWrapper.cpp b/xbmc/windowing/egl/EGLWrapper.cpp +index 045cdfc..0726cc2 100644 +--- a/xbmc/windowing/egl/EGLWrapper.cpp ++++ b/xbmc/windowing/egl/EGLWrapper.cpp +@@ -17,11 +17,10 @@ + * . + * + */ +- ++#include "EGLNativeTypeIMX.h" + #include "system.h" + + #ifdef HAS_EGL +- + #include "utils/log.h" + #include "EGLNativeTypeAndroid.h" + #include "EGLNativeTypeAmlogic.h" +@@ -83,7 +82,8 @@ bool CEGLWrapper::Initialize(const std::string &implementation) + if ((nativeGuess = CreateEGLNativeType(implementation)) || + (nativeGuess = CreateEGLNativeType(implementation)) || + (nativeGuess = CreateEGLNativeType(implementation)) || +- (nativeGuess = CreateEGLNativeType(implementation))) ++ (nativeGuess = CreateEGLNativeType(implementation)) || ++ (nativeGuess = CreateEGLNativeType(implementation))) + { + m_nativeTypes = nativeGuess; + +diff --git a/xbmc/windowing/egl/Makefile.in b/xbmc/windowing/egl/Makefile.in +index f800b7f..f59f9cb 100644 +--- a/xbmc/windowing/egl/Makefile.in ++++ b/xbmc/windowing/egl/Makefile.in +@@ -5,6 +5,7 @@ SRCS+= EGLNativeTypeAmlogic.cpp + SRCS+= EGLNativeTypeAndroid.cpp + SRCS+= EGLNativeTypeRaspberryPI.cpp + SRCS+= EGLNativeTypeWayland.cpp ++SRCS+= EGLNativeTypeIMX.cpp + SRCS+= EGLWrapper.cpp + + # Wayland specific detail +-- +1.9.3 + + +From 01ccb802fe0285c9bf83efee2d0f94c81afc6699 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Thu, 6 Feb 2014 16:26:29 +0100 +Subject: [PATCH 02/56] CHG: [imx] remove V4L and baseline software rendering + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 103 +- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 7 - + xbmc/cores/VideoRenderers/RenderFormats.h | 1 - + xbmc/cores/VideoRenderers/RenderManager.cpp | 4 - + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 7 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 1168 +++----------------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 110 +- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 - + xbmc/windowing/egl/EGLWrapper.cpp | 11 +- + xbmc/windowing/egl/Makefile.in | 5 +- + 10 files changed, 155 insertions(+), 1262 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 913fb0f..72eb725 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -20,10 +20,6 @@ + + //#define DEBUG_VERBOSE 1 + +-#ifdef HAS_IMXVPU +-#include +-#endif +- + #include "system.h" + #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS) + #include "config.h" +@@ -70,11 +66,6 @@ extern "C" { + #ifdef TARGET_DARWIN_IOS + #include "osx/DarwinUtils.h" + #endif +- +-#ifdef HAS_IMXVPU +-#include "DVDCodecs/Video/DVDVideoCodecIMX.h" +-#endif +- + #if defined(HAS_LIBSTAGEFRIGHT) + #include + #include +@@ -112,10 +103,6 @@ CLinuxRendererGLES::YUVBUFFER::YUVBUFFER() + #if defined(TARGET_ANDROID) + mediacodec = NULL; + #endif +-#ifdef HAS_IMXVPU +- imxOutputFrame = NULL; +-#endif +- + } + + CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER() +@@ -126,23 +113,6 @@ CLinuxRendererGLES::CLinuxRendererGLES() + { + m_textureTarget = GL_TEXTURE_2D; + +- /* FIXME a verifier */ +-#if 0 +- +- for (int i = 0; i < NUM_BUFFERS; i++) +- { +-#if defined(HAVE_LIBOPENMAX) +- m_buffers[i].openMaxBuffer = 0; +-#endif +-#ifdef HAVE_VIDEOTOOLBOXDECODER +- m_buffers[i].cvBufferRef = NULL; +-#endif +-#ifdef HAS_IMXVPU +- m_buffers[i].imx = NULL; +-#endif +- } +-#endif +- + m_renderMethod = RENDER_GLSL; + m_oldRenderMethod = m_renderMethod; + m_renderQuality = RQ_SINGLEPASS; +@@ -528,53 +498,18 @@ void CLinuxRendererGLES::RenderUpdate(bool clear, DWORD flags, DWORD alpha) + (*m_RenderUpdateCallBackFn)(m_RenderUpdateCallBackCtx, m_sourceRect, m_destRect); + + CRect old = g_graphicsContext.GetScissors(); +- RESOLUTION res = GetResolution(); +- int iWidth = CDisplaySettings::Get().GetResolutionInfo(res).iWidth; +- int iHeight = CDisplaySettings::Get().GetResolutionInfo(res).iHeight; + + g_graphicsContext.BeginPaint(); +- if (clear) +- { +- glScissor(0, +- 0, +- iWidth, +- iHeight); +- glClearColor(GLfloat(0.0), GLfloat(0.0), GLfloat(0.0), 0); +- glClear(GL_COLOR_BUFFER_BIT); +- } +- + g_graphicsContext.SetScissors(m_destRect); +- /* CLog::Log(LOGDEBUG, "%s - m_destRect : %f %f %f %f\n", +- __FUNCTION__, m_destRect.x1, m_destRect.x2, m_destRect.y1,m_destRect.y2);*/ +- + +-/* glEnable(GL_BLEND); +- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);*/ +- glClearColor(GLfloat(2.0/31.0), GLfloat(2.0/63.0), GLfloat(2.0/31.0), 0); ++ glEnable(GL_BLEND); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ++ glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + g_graphicsContext.SetScissors(old); + g_graphicsContext.EndPaint(); +- +-#ifdef HAS_IMXVPU +- // FIXME : move in its own render mode instead of mixup with BYPASS +- if (m_format == RENDER_FMT_IMX) +- { +- int index = m_iYV12RenderBuffer; +- struct v4l2_crop crop; +- crop.c.top = (int)m_destRect.y1; +- crop.c.left = (int)m_destRect.x1; +- crop.c.width = (int)(m_destRect.x2 - m_destRect.x1); +- crop.c.height = (int)(m_destRect.y2 - m_destRect.y1); +- CIMXOutputFrame *imxPicture = m_buffers[index].imxOutputFrame; +- if (imxPicture != NULL) +- { +- imxPicture->Render(crop); +- m_buffers[index].imxOutputFrame = NULL; +- } +- } + return; +-#endif + } + + // this needs to be checked after texture validation +@@ -663,9 +598,6 @@ unsigned int CLinuxRendererGLES::PreInit() + #ifdef HAVE_VIDEOTOOLBOXDECODER + m_formats.push_back(RENDER_FMT_CVBREF); + #endif +-#ifdef HAS_IMXVPU +- m_formats.push_back(RENDER_FMT_IMX); +-#endif + #ifdef HAS_LIBSTAGEFRIGHT + m_formats.push_back(RENDER_FMT_EGLIMG); + #endif +@@ -791,13 +723,6 @@ void CLinuxRendererGLES::LoadShaders(int field) + m_renderMethod = RENDER_CVREF; + break; + } +- else if (m_format == RENDER_FMT_IMX) +- { +- CLog::Log(LOGNOTICE, "GL: IMX format Uses BYPASS render method"); +- m_renderMethod = RENDER_BYPASS; +- break; +- } +- + #if defined(TARGET_DARWIN_IOS) + else if (ios_version < 5.0 && m_format == RENDER_FMT_YUV420P) + { +@@ -968,18 +893,6 @@ void CLinuxRendererGLES::ReleaseBuffer(int idx) + } + } + #endif +-#ifdef HAS_IMXVPU +- if (buf.imxOutputFrame != NULL) +- { +- // If we take that branch the buffer was not queued to V4L2 +- // So release the picture now so that VPU will be given +- // the buffer back as soon as next ::Decode() call +- buf.imxOutputFrame->Release(); +- buf.imxOutputFrame = NULL; +- } +- return; +-#endif +- + } + + void CLinuxRendererGLES::Render(DWORD flags, int index) +@@ -2778,15 +2691,6 @@ void CLinuxRendererGLES::AddProcessor(struct __CVBuffer *cvBufferRef, int index) + CVBufferRetain(buf.cvBufferRef); + } + #endif +- +-#ifdef HAS_IMXVPU +-void CLinuxRendererGLES::AddProcessor(CIMXOutputFrame *imx, int index) +-{ +- YUVBUFFER &buf = m_buffers[index]; +- buf.imxOutputFrame = imx; +-} +-#endif +- + #ifdef HAS_LIBSTAGEFRIGHT + void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index) + { +@@ -2808,7 +2712,6 @@ void CLinuxRendererGLES::AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKH + } + #endif + +- + #if defined(TARGET_ANDROID) + void CLinuxRendererGLES::AddProcessor(CDVDMediaCodecInfo *mediacodec, int index) + { +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index e58330a..642cded 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -42,7 +42,6 @@ namespace Shaders { class BaseVideoFilterShader; } + class COpenMaxVideo; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; +-class CIMXOutputFrame; + typedef std::vector Features; + + +@@ -167,9 +166,6 @@ class CLinuxRendererGLES : public CBaseRenderer + #ifdef HAS_LIBSTAGEFRIGHT + virtual void AddProcessor(CDVDVideoCodecStageFright* stf, EGLImageKHR eglimg, int index); + #endif +-#ifdef HAS_IMXVPU +- virtual void AddProcessor(CIMXOutputFrame *imx, int index); +-#endif + #if defined(TARGET_ANDROID) + // mediaCodec + virtual void AddProcessor(CDVDMediaCodecInfo *mediacodec, int index); +@@ -281,9 +277,6 @@ class CLinuxRendererGLES : public CBaseRenderer + #ifdef HAVE_VIDEOTOOLBOXDECODER + struct __CVBuffer *cvBufferRef; + #endif +-#ifdef HAS_IMXVPU +- CIMXOutputFrame *imxOutputFrame; +-#endif + #ifdef HAS_LIBSTAGEFRIGHT + CDVDVideoCodecStageFright* stf; + EGLImageKHR eglimg; +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index d40e4f5..f15e80d 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -35,7 +35,6 @@ enum ERenderFormat { + RENDER_FMT_OMXEGL, + RENDER_FMT_CVBREF, + RENDER_FMT_BYPASS, +- RENDER_FMT_IMX, + RENDER_FMT_EGLIMG, + RENDER_FMT_MEDIACODEC, + }; +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index a9d071d..6832721 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -922,10 +922,6 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + else if(pic.format == RENDER_FMT_VAAPI) + m_pRenderer->AddProcessor(*pic.vaapi, index); + #endif +-#ifdef HAS_IMXVPU +- else if(pic.format == RENDER_FMT_IMX) +- m_pRenderer->AddProcessor(pic.imxOutputFrame, index); +-#endif + #ifdef HAS_LIBSTAGEFRIGHT + else if(pic.format == RENDER_FMT_EGLIMG) + m_pRenderer->AddProcessor(pic.stf, pic.eglimg, index); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 3e61edc..1553789 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -49,7 +49,6 @@ namespace VDPAU { class CVdpauRenderPicture; } + class COpenMax; + class COpenMaxVideo; + struct OpenMaxVideoBuffer; +-class CIMXOutputFrame; + class CDVDVideoCodecStageFright; + class CDVDMediaCodecInfo; + typedef void* EGLImageKHR; +@@ -76,16 +75,14 @@ struct DVDVideoPicture + struct { + VAAPI::CHolder* vaapi; + }; ++ + struct { + COpenMax *openMax; + OpenMaxVideoBuffer *openMaxBuffer; + }; +- struct { +- struct __CVBuffer *cvBufferRef; +- }; + + struct { +- CIMXOutputFrame *imxOutputFrame; ++ struct __CVBuffer *cvBufferRef; + }; + + struct { +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index c0af493..9adffd3 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -32,484 +32,8 @@ + #include "mfw_gst_ts.h" + #include "threads/Atomics.h" + +-//#define NO_V4L_RENDERING + +-#ifdef IMX_PROFILE +-static unsigned long long render_ts[30]; +-static unsigned long long get_time() +-{ +- struct timespec ts; +- unsigned long long now; +- +- clock_gettime(CLOCK_MONOTONIC, &ts); +- now = (((unsigned long long)ts.tv_sec) * 1000000000ULL) + +- ((unsigned long long)ts.tv_nsec); +- +- return now; +-} +-#endif +- +-void CIMXOutputFrame::Render(struct v4l2_crop &crop) +-{ +- CIMXRenderingFrames& renderingFrames = CIMXRenderingFrames::GetInstance(); +- renderingFrames.Queue(this, crop); +-} +- +-/* video device on which the video will be rendered (/dev/video17 => /dev/fb1) */ +-const char *CIMXRenderingFrames::m_v4lDeviceName = "/dev/video17"; +-static long sg_singleton_lock_variable = 0; +-CIMXRenderingFrames* CIMXRenderingFrames::m_instance = 0; +- +-CIMXRenderingFrames& +-CIMXRenderingFrames::GetInstance() +-{ +- CAtomicSpinLock lock(sg_singleton_lock_variable); +- if( ! m_instance ) +- { +- m_instance = new CIMXRenderingFrames(); +- } +- return *m_instance; +-} +- +-CIMXRenderingFrames::CIMXRenderingFrames() +-{ +- m_ready = false; +- m_v4lfd = -1; +- m_virtAddr = NULL; +- m_v4lBuffers = NULL; +- memset(&m_crop, 0, sizeof(m_crop)); +- m_crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- m_motionCtrl = -1; +-} +- +-bool CIMXRenderingFrames::AllocateBuffers(const struct v4l2_format *format, int nbBuffers) +-{ +- int ret, i; +- struct v4l2_requestbuffers bufReq; +- struct v4l2_format fmt; +- struct v4l2_buffer v4lBuf; +- struct v4l2_control ctrl; +- +- CSingleLock lock(m_renderingFramesLock); +- if (m_ready) +- { +- CLog::Log(LOGERROR, "%s - Try to re-allocate buffers while previous buffers were not freed.\n", __FUNCTION__); +- return false; +- } +- +- m_v4lfd = open(m_v4lDeviceName, O_RDWR|O_NONBLOCK, 0); +- if (m_v4lfd < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while trying to open %s.\n", __FUNCTION__, m_v4lDeviceName); +- __ReleaseBuffers(); +- return false; +- } +- +- ret = ioctl(m_v4lfd, VIDIOC_S_FMT, format); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while setting V4L format (ret %d : %s).\n", __FUNCTION__, ret, strerror(errno)); +- __ReleaseBuffers(); +- return false; +- } +- +- if (format->fmt.pix.field != V4L2_FIELD_NONE) +- { +- char * motion_entry; +- motion_entry = getenv("IMX_DEINT_MOTION"); +- if (motion_entry != NULL) +- { +- errno = 0; +- m_motionCtrl = strtol(motion_entry, NULL, 10); +- if (errno != 0) +- m_motionCtrl = -1; +- } +- if (m_motionCtrl == -1) +- m_motionCtrl = 2; /* Default value : 2 stands for high motion */ +- +- if ((m_motionCtrl >= 0) && (m_motionCtrl <=2)) +- { +- ctrl.id = V4L2_CID_MXC_MOTION; +- ctrl.value = m_motionCtrl; +- ret = ioctl (m_v4lfd, VIDIOC_S_CTRL, &ctrl); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while setting V4L motion (ret %d : %s).\n", __FUNCTION__, ret, strerror(errno)); +- } +- } +- else +- { +- CLog::Log(LOGNOTICE, "%s - IMX_DEINT_MOTION set to %d. Disabling deinterlacing.\n", __FUNCTION__, m_motionCtrl); +- m_motionCtrl = -2; +- } +- } +- +- fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- ret = ioctl(m_v4lfd, VIDIOC_G_FMT, &fmt); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while getting V4L format (ret %d : %s).\n", __FUNCTION__, ret, strerror(errno)); +- __ReleaseBuffers(); +- return false; +- } +- +- m_bufferNum = nbBuffers; +- /* Alloc V4L2 buffers */ +- memset(&bufReq, 0, sizeof(bufReq)); +- bufReq.count = m_bufferNum; +- bufReq.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- bufReq.memory = V4L2_MEMORY_MMAP; +- ret = ioctl(m_v4lfd, VIDIOC_REQBUFS, &bufReq); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - %d Hw buffer allocation error (%d)\n", __FUNCTION__, bufReq.count, ret); +- __ReleaseBuffers(); +- return false; +- } +- CLog::Log(LOGDEBUG, "%s - %d Hw buffer of %d bytes allocated\n", __FUNCTION__, bufReq.count, fmt.fmt.pix.sizeimage); +- +- m_virtAddr = new void*[m_bufferNum]; +- if (m_virtAddr == NULL) +- { +- CLog::Log(LOGERROR, "%s - Allocation failure (m_virtAddr table of %d elements)\n", __FUNCTION__, m_bufferNum); +- __ReleaseBuffers(); +- return false; +- } +- m_v4lBuffers = new v4l2_buffer[m_bufferNum]; +- if (m_v4lBuffers == NULL) +- { +- CLog::Log(LOGERROR, "%s - Allocation failure (m_v4lBuffers table of %d elements)\n", __FUNCTION__, m_bufferNum); +- __ReleaseBuffers(); +- return false; +- } +- +- for (i = 0 ; i < m_bufferNum; i++) +- { +- memset(&v4lBuf, 0, sizeof(v4lBuf)); +- v4lBuf.index = i; +- v4lBuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- v4lBuf.memory = V4L2_MEMORY_MMAP; +- ret = ioctl (m_v4lfd, VIDIOC_QUERYBUF, &v4lBuf); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - Error during 1st query of V4L buffer (ret %d : %s)\n", __FUNCTION__, ret, strerror(errno)); +- return false; +- } +- m_v4lBuffers[i] = v4lBuf; +- m_virtAddr[i] = NULL; +- } +- memset(&m_crop, 0, sizeof(m_crop)); +- m_crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- m_pushedFrames = 0; +- m_streamOn = false; +- m_ready = true; +- return true; +-} +- +-void *CIMXRenderingFrames::GetVirtAddr(int idx) +-{ +- struct v4l2_buffer v4lBuf; +- int ret; +- +- CSingleLock lock(m_renderingFramesLock); +- if (!m_ready) +- return NULL; +- if ((idx < 0) || (idx >= m_bufferNum)) +- return NULL; +- +- if (m_virtAddr[idx] == NULL) +- { +- v4lBuf = m_v4lBuffers[idx]; +- m_virtAddr[idx] = mmap(NULL, v4lBuf.length, PROT_READ | PROT_WRITE, MAP_SHARED, m_v4lfd, v4lBuf.m.offset); +- +- /* 2nd query to retrieve real Physical address after mmap (iMX6 bug) */ +- ret = ioctl (m_v4lfd, VIDIOC_QUERYBUF, &v4lBuf); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - Error during 2nd query of V4L buffer (ret %d : %s)\n", __FUNCTION__, ret, strerror(errno)); +- } +- m_v4lBuffers[idx] = v4lBuf; +- } +- return m_virtAddr[idx]; +-} +- +-void *CIMXRenderingFrames::GetPhyAddr(int idx) +-{ +- +- CSingleLock lock(m_renderingFramesLock); +- if (!m_ready) +- return NULL; +- if ((idx < 0) || (idx >= m_bufferNum)) +- return NULL; +- +- return (void *)m_v4lBuffers[idx].m.offset; +-} +- +-int CIMXRenderingFrames::FindBuffer(void *phyAddr) +-{ +- int i; +- +- CSingleLock lock(m_renderingFramesLock); +- if (!m_ready) +- return -1; +- +- for (i = 0; i < m_bufferNum; i++) +- { +- if (m_v4lBuffers[i].m.offset == (unsigned int)phyAddr) +- { +- // CLog::Log(LOGNOTICE, "%s - found buffer OK %d!\n", __FUNCTION__, i); +- return i; +- } +- } +- return -1; +-} +- +-int CIMXRenderingFrames::DeQueue(bool wait) +-{ +- int ret; +- int status; +- struct v4l2_buffer buf; +- +- CSingleLock lock(m_renderingFramesLock); +- if (!m_ready) +- { +- CLog::Log(LOGNOTICE, "%s - Cannot dequeue frame as buffers were released !\n", +- __FUNCTION__); +- return -1; +- } +- if (!m_streamOn) +- { +- return -1; +- } +- +- if (wait) +- { +- status = fcntl(m_v4lfd, F_GETFL); +- fcntl(m_v4lfd, F_SETFL, status & (~O_NONBLOCK)); +- } +- buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- buf.memory = V4L2_MEMORY_MMAP; +- ret = ioctl(m_v4lfd, VIDIOC_DQBUF, &buf); +- if (wait) +- { +- fcntl(m_v4lfd, F_SETFL, status | O_NONBLOCK); +- } +- if (ret != 0) +- { +- if (errno != EAGAIN) +- CLog::Log(LOGERROR, "%s - Dequeue buffer error (ret %d : %s)\n", +- __FUNCTION__, ret, strerror(errno)); +- return -1; +- } +- +-#ifdef IMX_PROFILE +- CLog::Log(LOGDEBUG, "%s - Time render to dequeue (%d) %llu\n", +- __FUNCTION__, buf.index, get_time() - render_ts[buf.index]); +-#endif +-// CLog::Log(LOGERROR, "%s dequeued retuns (%d)\n", __FUNCTION__, buf.index); +- +- return buf.index; +-} +- +-void CIMXRenderingFrames::Queue(CIMXOutputFrame *picture, struct v4l2_crop &destRect) +-{ +- /* Warning : called from renderer thread +- * Especially do not call any VPU functions as they are not thread safe +- */ +- +- int ret, type; +- struct timeval queue_ts; +- int stream_trigger; +- bool crop_update = false; +- +- CSingleLock lock(m_renderingFramesLock); +- if (!m_ready) +- { +- CLog::Log(LOGNOTICE, "%s - Cannot queue frame as buffers were released !\n", +- __FUNCTION__); +- return; +- } +- +- /*CLog::Log(LOGDEBUG, "%s - queuing frame %d - picture adress : %p\n", +- __FUNCTION__, picture->v4l2BufferIdx, picture);*/ +- +- if ((picture->v4l2BufferIdx < 0) || (picture->v4l2BufferIdx >= m_bufferNum)) +- { +- CLog::Log(LOGERROR, "%s - Invalid buffer index : %d - picture address : %p\n", +- __FUNCTION__, picture->v4l2BufferIdx, picture); +- return; +- } +- +- /* Set field type for each buffer otherwise the mxc_vout driver reverts to progressive */ +- switch (picture->field) +- { +- case VPU_FIELD_TB: +- m_v4lBuffers[picture->v4l2BufferIdx].field = V4L2_FIELD_INTERLACED_TB; +- break; +- case VPU_FIELD_BT: +- m_v4lBuffers[picture->v4l2BufferIdx].field= V4L2_FIELD_INTERLACED_BT; +- break; +- case VPU_FIELD_NONE: +- default: +- m_v4lBuffers[picture->v4l2BufferIdx].field = V4L2_FIELD_NONE; +- break; +- } +- /* In case deinterlacing is forced to disabled */ +- if (m_motionCtrl == -2) +- m_v4lBuffers[picture->v4l2BufferIdx].field = V4L2_FIELD_NONE; +- +- /* mxc_vout driver does not display immediatly +- * if timestamp is set to 0 +- * (instead this driver expects a 30fps rate) +- * So we explicitly set current time for immediate display +- */ +- gettimeofday (&queue_ts, NULL); +- m_v4lBuffers[picture->v4l2BufferIdx].timestamp = queue_ts; +- +-#ifndef NO_V4L_RENDERING +- ret = ioctl(m_v4lfd, VIDIOC_QBUF, &m_v4lBuffers[picture->v4l2BufferIdx]); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - V4L Queue buffer failed (ret %d : %s)\n", +- __FUNCTION__, ret, strerror(errno)); +- /* If it fails odds are very high picture is invalid so just exit now */ +- return; +- } +- else +- { +- m_pushedFrames++; +- } +- +- /* Force cropping dimensions to be aligned */ +- destRect.c.top &= 0xFFFFFFF8; +- destRect.c.left &= 0xFFFFFFF8; +- destRect.c.width &= 0xFFFFFFF8; +- destRect.c.height &= 0xFFFFFFF8; +- if ((m_crop.c.top != destRect.c.top) || +- (m_crop.c.left != destRect.c.left) || +- (m_crop.c.width != destRect.c.width) || +- (m_crop.c.height != destRect.c.height)) +- { +- CLog::Log(LOGNOTICE, "%s - Newcrop : %d % d %d %d\n", +- __FUNCTION__, destRect.c.top, destRect.c.left, destRect.c.width, destRect.c.height); +- m_crop.c = destRect.c; +- crop_update = true; +- } +- +- if (!m_streamOn) +- { +- if (picture->field == VPU_FIELD_NONE) +- stream_trigger = 1; +- else { +- if (m_motionCtrl < 2) +- stream_trigger = 3; +- else +- stream_trigger = 2; +- } +- +- if (m_pushedFrames >= stream_trigger) { +- CLog::Log(LOGDEBUG, "%s - Motion control is : %d - Number of required frames before streaming : %d\n", +- __FUNCTION__, m_motionCtrl, stream_trigger); +- +- type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- ret = ioctl(m_v4lfd, VIDIOC_STREAMON, &type); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - V4L Stream ON failed (ret %d : %s)\n", +- __FUNCTION__, ret, strerror(errno)); +- } +- else +- { +- CLog::Log(LOGDEBUG, "%s - V4L Stream ON OK\n", +- __FUNCTION__); +- m_streamOn = true; +- } +- /* We have to repeat crop command after streamon for some vids +- * FIXME : Check why in drivers... +- */ +- ret = ioctl(m_v4lfd, VIDIOC_S_CROP, &m_crop); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - S_CROP failed (ret %d : %s)\n", +- __FUNCTION__, ret, strerror(errno)); +- } +- } +- } +- else +- { +- if (crop_update) +- { +- ret = ioctl(m_v4lfd, VIDIOC_S_CROP, &m_crop); +- if (ret < 0) +- { +- CLog::Log(LOGERROR, "%s - S_CROP failed (ret %d : %s)\n", +- __FUNCTION__, ret, strerror(errno)); +- } +- } +- } +-#endif +- +-#ifdef IMX_PROFILE +- render_ts[picture->v4l2BufferIdx] = get_time(); +- CLog::Log(LOGDEBUG, "%s - Time push to render (%d) %llu\n", +- __FUNCTION__, picture->v4l2BufferIdx, render_ts[picture->v4l2BufferIdx] - picture->pushTS); +-#endif +-} +- +-void CIMXRenderingFrames::ReleaseBuffers() +-{ +- CSingleLock lock(m_renderingFramesLock); +- if (!m_ready) +- { +- CLog::Log(LOGERROR, "%s - AllocateBuffers was not previously called\n", __FUNCTION__); +- return; +- } +- __ReleaseBuffers(); +-} +- +-/* Note : Has to be called with m_renderingFramesLock held */ +-void CIMXRenderingFrames::__ReleaseBuffers() +-{ +- int type, i; +- +- if (m_v4lfd >= 0) +- { +- /* stream off */ +- type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- ioctl (m_v4lfd, VIDIOC_STREAMOFF, &type); +- m_streamOn = false; +- } +- +- if (m_virtAddr != NULL) +- { +- for (i = 0; i < m_bufferNum; i++) +- { +- if (m_virtAddr[i] != NULL) +- munmap (m_virtAddr[i], m_v4lBuffers[i].length); +- } +- delete m_virtAddr; +- m_virtAddr = NULL; +- } +- +- if (m_v4lfd >= 0) +- { +- /* Close V4L2 device */ +- close(m_v4lfd); +- m_v4lfd = -1; +- } +- +- if (m_v4lBuffers != NULL) +- { +- delete m_v4lBuffers; +- m_v4lBuffers = NULL; +- } +- m_bufferNum = 0; +- m_pushedFrames = 0; +- m_ready = false; +- m_motionCtrl = -1; +-} +- +-/* FIXME get rid of these defines properly */ ++// 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)) +@@ -517,30 +41,9 @@ void CIMXRenderingFrames::__ReleaseBuffers() + #define min(a, b) (aGetClock() / DVD_TIME_BASE; +- +- return clock_pts; +-} +- +-void CDVDVideoCodecIMX::FlushDecodedFrames(void) +-{ +- DVDVideoPicture DVDFrame; +- while (m_decodedFrames.size() > 0) +- { +- DVDFrame = m_decodedFrames.front(); +- VpuReleaseBufferV4L(DVDFrame.imxOutputFrame->v4l2BufferIdx); +- m_decodedFrames.pop(); +- } +-} +- + bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + { + int i, size; +@@ -694,269 +197,113 @@ bool CDVDVideoCodecIMX::VpuOpen(void) + return false; + } + +-void CDVDVideoCodecIMX::InitFB(void) +-{ +- struct mxcfb_gbl_alpha alpha; +- struct mxcfb_color_key colorKey; +- int fd; +- +- fd = open("/dev/fb0",O_RDWR); +- /* set FG/BG semi opaque */ +- alpha.alpha = 235; +- alpha.enable = 1; +- ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha); +- /* Enable color keying */ +- colorKey.enable = 1; +- colorKey.color_key = (16 << 16) | (8 << 8) | 16; +- if (ioctl(fd, MXCFB_SET_CLR_KEY, &colorKey) < 0) +- CLog::Log(LOGERROR, "%s - Error while trying to enable color keying %s.\n", __FUNCTION__, strerror(errno)); +- close(fd); +-} +- +-void CDVDVideoCodecIMX::RestoreFB(void) +-{ +- struct mxcfb_gbl_alpha alpha; +- struct mxcfb_color_key colorKey; +- int fd; +- +- fd = open("/dev/fb0",O_RDWR); +- /* set FG as opaque */ +- alpha.alpha = 255; +- alpha.enable = 1; +- ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha); +- /* Disable color keying */ +- colorKey.enable = 0; +- colorKey.color_key = 0; +- if (ioctl(fd, MXCFB_SET_CLR_KEY, &colorKey) < 0) +- CLog::Log(LOGERROR, "%s - Error while trying to disable color keying %s.\n", __FUNCTION__, strerror(errno)); +- close(fd); +-} +- + bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + { +- /* Alloc frame buffers from V4L2 for efficient rendering through V4L streaming */ +- struct v4l2_format fmt; +- struct v4l2_rect rect; +- int i, j; +- int ySize, cSize; +- VpuDecRetCode vpuRet; +- +- InitFB(); +- +- /* Set V4L2 Format */ +- memset(&fmt, 0, sizeof(fmt)); +- fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; +- fmt.fmt.pix.width = Align( m_initInfo.nPicWidth, FRAME_ALIGN); +- fmt.fmt.pix.height = Align(m_initInfo.nPicHeight, FRAME_ALIGN); +- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; +- /* Take into account cropping from decoded video (for input picture) */ +- rect.left = m_initInfo.PicCropRect.nLeft; +- rect.top = m_initInfo.PicCropRect.nTop; +- rect.width = m_initInfo.PicCropRect.nRight - m_initInfo.PicCropRect.nLeft; +- rect.height = m_initInfo.PicCropRect.nBottom - m_initInfo.PicCropRect.nTop; +- fmt.fmt.pix.priv = (unsigned int)▭ ++ VpuDecRetCode ret; ++ VpuMemDesc vpuMem; ++ int i; ++ int totalSize=0; ++ int mvSize=0; ++ int ySize=0; ++ int uSize=0; ++ int vSize=0; ++ int yStride=0; ++ int uStride=0; ++ int vStride=0; ++ unsigned char* ptr; ++ unsigned char* ptrVirt; ++ int nAlign; + + m_vpuFrameBufferNum = m_initInfo.nMinFrameBufferCount + m_extraVpuBuffers; +- if (m_initInfo.nInterlace) +- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED_TB; ++ 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 +- fmt.fmt.pix.field = V4L2_FIELD_NONE; +- if (!m_renderingFrames.AllocateBuffers(&fmt, m_vpuFrameBufferNum)) + { +- return false; ++ ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN); + } + +- m_outputBuffers = new VpuV4LFrameBuffer[m_vpuFrameBufferNum]; +- m_vpuFrameBuffers = new VpuFrameBuffer[m_vpuFrameBufferNum]; +- m_extraMem = new VpuMemDesc[m_vpuFrameBufferNum]; +- ySize = fmt.fmt.pix.width * fmt.fmt.pix.height; +- cSize = ySize / 4; +- for (i = 0 ; i < m_vpuFrameBufferNum; i++) ++ //4:2:0 for all video ++ uStride=yStride/2; ++ vStride=uStride; ++ uSize=ySize/4; ++ vSize=uSize; ++ mvSize=uSize; ++ ++ nAlign=m_initInfo.nAddressAlignment; ++ if(nAlign>1) + { +- m_vpuFrameBuffers[i].pbufVirtY = (unsigned char *)m_renderingFrames.GetVirtAddr(i); +- m_vpuFrameBuffers[i].nStrideY = fmt.fmt.pix.width; +- m_vpuFrameBuffers[i].nStrideC = m_vpuFrameBuffers[i].nStrideY / 2; +- m_vpuFrameBuffers[i].pbufY = (unsigned char *)m_renderingFrames.GetPhyAddr(i); +- m_vpuFrameBuffers[i].pbufCb = m_vpuFrameBuffers[i].pbufY + ySize; +- m_vpuFrameBuffers[i].pbufCr = m_vpuFrameBuffers[i].pbufCb + cSize; +- m_vpuFrameBuffers[i].pbufVirtCb = m_vpuFrameBuffers[i].pbufVirtY + ySize; +- m_vpuFrameBuffers[i].pbufVirtCr = m_vpuFrameBuffers[i].pbufVirtCb + cSize; +- /* Dont care about tile */ +- m_vpuFrameBuffers[i].pbufY_tilebot = 0; +- m_vpuFrameBuffers[i].pbufCb_tilebot = 0; +- m_vpuFrameBuffers[i].pbufVirtY_tilebot = 0; +- m_vpuFrameBuffers[i].pbufVirtCb_tilebot = 0; +- m_outputBuffers[i].clear(); ++ ySize=Align(ySize,nAlign); ++ uSize=Align(uSize,nAlign); ++ vSize=Align(vSize,nAlign); + } + +- /* Allocate physical extra memory */ + for (i = 0 ; i < m_vpuFrameBufferNum; i++) + { +- m_extraMem[i].nSize = cSize; +- vpuRet = VPU_DecGetMem(&m_extraMem[i]); +- if (vpuRet != VPU_DEC_RET_SUCCESS) ++ totalSize=(ySize+uSize+vSize+mvSize+nAlign)*1; ++ ++ vpuMem.nSize=totalSize; ++ ret = VPU_DecGetMem(&vpuMem); ++ if(ret != VPU_DEC_RET_SUCCESS) + { +- CLog::Log(LOGERROR, "%s - Extra memory (%d bytes) allocation failure (%d).\n", +- __FUNCTION__, m_extraMem[i].nSize , vpuRet); +- for (j=i ; jpDisplayFrameBuf; +- CIMXOutputFrame *outputFrame; +- int i; +- double pts; +- DVDVideoPicture DVDFrame; +- +- // FIXME pts = (double)TSManagerSend2(m_tsm, frameBuffer) / (double)1000.0; +- pts = (double)TSManagerSend(m_tsm) / (double)1000.0; +- /* Find Frame given physical address */ +- i = m_renderingFrames.FindBuffer(frameBuffer->pbufY); +- if (i == -1) +- { +- CLog::Log(LOGERROR, "%s - V4L buffer not found\n", __FUNCTION__); +- return false; +- } +- if (m_outputBuffers[i].used()) +- { +- CLog::Log(LOGERROR, "%s - Try to reuse buffer which was not dequeued !\n", __FUNCTION__); +- return false; +- } ++ //record memory info for release ++ m_decMemInfo.phyMem_phyAddr[m_decMemInfo.nPhyNum]=vpuMem.nPhyAddr; ++ m_decMemInfo.phyMem_virtAddr[m_decMemInfo.nPhyNum]=vpuMem.nVirtAddr; ++ m_decMemInfo.phyMem_cpuAddr[m_decMemInfo.nPhyNum]=vpuMem.nCpuAddr; ++ m_decMemInfo.phyMem_size[m_decMemInfo.nPhyNum]=vpuMem.nSize; ++ m_decMemInfo.nPhyNum++; + +- /* Store the pointer to be able to invoke VPU_DecOutFrameDisplayed when the buffer will be dequeued */ +- m_outputBuffers[i].store(frameBuffer, m_frameCounter++); +- +- outputFrame = &m_outputBuffers[i].outputFrame; +- outputFrame->v4l2BufferIdx = i; +- outputFrame->field = frameInfo->eFieldType; +- outputFrame->picCrop = frameInfo->pExtInfo->FrmCropRect; +- outputFrame->nQ16ShiftWidthDivHeightRatio = frameInfo->pExtInfo->nQ16ShiftWidthDivHeightRatio; +- DVDFrame.imxOutputFrame = outputFrame; +- +- DVDFrame.pts = pts; +- DVDFrame.dts = DVD_NOPTS_VALUE; +- /* +- m_outputFrame.iWidth = frameInfo->pExtInfo->nFrmWidth; +- m_outputFrame.iHeight = frameInfo->pExtInfo->nFrmHeight; +- */ +- DVDFrame.iWidth = frameInfo->pExtInfo->FrmCropRect.nRight - frameInfo->pExtInfo->FrmCropRect.nLeft; +- DVDFrame.iHeight = frameInfo->pExtInfo->FrmCropRect.nBottom - frameInfo->pExtInfo->FrmCropRect.nTop; +- DVDFrame.format = RENDER_FMT_IMX; +- +- m_decodedFrames.push(DVDFrame); +- if (m_decodedFrames.size() > IMX_MAX_QUEUE_SIZE) +- { +- CLog::Log(LOGERROR, "%s - Too many enqueued decoded frames : %d (Max %d)\n", __FUNCTION__, m_decodedFrames.size(), IMX_MAX_QUEUE_SIZE); +- } ++ //fill frameBuf ++ ptr=(unsigned char*)vpuMem.nPhyAddr; ++ ptrVirt=(unsigned char*)vpuMem.nVirtAddr; + +-#ifdef IMX_PROFILE +- DVDFrame.imxOutputFrame->pushTS = get_time(); +- CLog::Log(LOGDEBUG, "%s - push (%i) Time between push %llu\n", +- __FUNCTION__, i, DVDFrame.imxOutputFrame->pushTS - previous_ts); +- previous_ts =DVDFrame.imxOutputFrame->pushTS; +-#endif ++ /*align the base address*/ ++ if(nAlign>1) ++ { ++ ptr=(unsigned char*)Align(ptr,nAlign); ++ ptrVirt=(unsigned char*)Align(ptrVirt,nAlign); ++ } + +- return true; +-} ++ /* fill stride info */ ++ m_vpuFrameBuffers[i].nStrideY=yStride; ++ m_vpuFrameBuffers[i].nStrideC=uStride; + +-int CDVDVideoCodecIMX::GetAvailableBufferNb(void) +-{ +- int i, nb; ++ /* fill phy addr*/ ++ m_vpuFrameBuffers[i].pbufY=ptr; ++ m_vpuFrameBuffers[i].pbufCb=ptr+ySize; ++ m_vpuFrameBuffers[i].pbufCr=ptr+ySize+uSize; ++ m_vpuFrameBuffers[i].pbufMvCol=ptr+ySize+uSize+vSize; ++ //ptr+=ySize+uSize+vSize+mvSize; ++ /* fill virt addr */ ++ m_vpuFrameBuffers[i].pbufVirtY=ptrVirt; ++ m_vpuFrameBuffers[i].pbufVirtCb=ptrVirt+ySize; ++ m_vpuFrameBuffers[i].pbufVirtCr=ptrVirt+ySize+uSize; ++ m_vpuFrameBuffers[i].pbufVirtMvCol=ptrVirt+ySize+uSize+vSize; ++ //ptrVirt+=ySize+uSize+vSize+mvSize; + +- nb = 0; +- for (i = 0; i < m_vpuFrameBufferNum; i++) +- { +- if (!m_outputBuffers[i].used()) +- nb++; ++ m_vpuFrameBuffers[i].pbufY_tilebot=0; ++ m_vpuFrameBuffers[i].pbufCb_tilebot=0; ++ m_vpuFrameBuffers[i].pbufVirtY_tilebot=0; ++ m_vpuFrameBuffers[i].pbufVirtCb_tilebot=0; + } +- return nb; +-} + +-bool CDVDVideoCodecIMX::VpuReleaseBufferV4L(int idx) +-{ +- if (idx < 0 || idx >= m_vpuFrameBufferNum) +- { +- CLog::Log(LOGERROR, "%s - Invalid index - idx : %d\n", __FUNCTION__, idx); +- return false; +- } +- +- /*CLog::Log(LOGDEBUG, "%s - idx : %d - frame : %d\n", __FUNCTION__, +- idx, m_outputBuffers[idx].frameNo);*/ +- +- VPU_DecOutFrameDisplayed(m_vpuHandle, m_outputBuffers[idx].buffer); +- m_outputBuffers[idx].clear(); + return true; + } + +-/* Dequeue queued frames and free the corresponding VPU buffers */ +-bool CDVDVideoCodecIMX::VpuDeQueueFrame(bool wait) +-{ +- int idx, i, frameNo; +- +- idx = m_renderingFrames.DeQueue(wait); +- if (idx != -1) +- { +- if (!m_outputBuffers[idx].used()) +- { +- CLog::Log(LOGERROR, "%s - WTF : associated buffer does not exist anymore\n", +- __FUNCTION__); +- return true; +- } +- else +- { +- frameNo = m_outputBuffers[idx].frameNo(); +- VpuReleaseBufferV4L(idx); +- if (frameNo > 0) +- { +- /* Release buffers which are not used anymore and were +- * queued before the idx buffer that has just been dequeued*/ +- for (i = 0; i < m_vpuFrameBufferNum; ++i) +- { +- if (m_outputBuffers[i].expired(frameNo)) +- { +- CLog::Log(LOGNOTICE, "%s - Release expired buffer - idx : %d\n", __FUNCTION__, i); +- VpuReleaseBufferV4L(i); +- } +- } +- } +- return true; +- } +- } +- else +- { +-#ifdef NO_V4L_RENDERING +- int i; +- for (i = 0; i < m_vpuFrameBufferNum; i++) +- { +- if (m_outputBuffers[i].used()) +- { +- VpuReleaseBufferV4L(idx); +- } +- } +-#endif +- return false; +- } +-} +- +-CDVDVideoCodecIMX::CDVDVideoCodecIMX() : m_renderingFrames(CIMXRenderingFrames::GetInstance()) ++CDVDVideoCodecIMX::CDVDVideoCodecIMX() + { + m_pFormatName = "iMX-xxx"; + memset(&m_decMemInfo, 0, sizeof(DecMemInfo)); + m_vpuHandle = 0; + m_vpuFrameBuffers = NULL; +- m_outputBuffers = NULL; + m_extraMem = NULL; + m_vpuFrameBufferNum = 0; + m_tsSyncRequired = true; +@@ -1028,11 +375,14 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + case CODEC_ID_H264: + m_decOpenParam.CodecFormat = VPU_V_AVC; + m_pFormatName = "iMX-h264"; +- if (hints.extradata) ++ if (hints.extrasize < 7 || hints.extradata == NULL) + { +- if ( *(char*)hints.extradata == 1 ) +- m_convert_bitstream = bitstream_convert_init(hints.extradata,hints.extrasize); ++ CLog::Log(LOGNOTICE, ++ "%s - avcC data too small or missing", __FUNCTION__); ++ return false; + } ++ 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; +@@ -1103,10 +453,8 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + void CDVDVideoCodecIMX::Dispose(void) + { + VpuDecRetCode ret; +- int i; + bool VPU_loaded = m_vpuHandle; + +- FlushDecodedFrames(); + if (m_vpuHandle) + { + ret = VPU_DecFlushAll(m_vpuHandle); +@@ -1123,34 +471,6 @@ void CDVDVideoCodecIMX::Dispose(void) + } + + VpuFreeBuffers(); +- +- if (m_outputBuffers != NULL) +- { +- while (VpuDeQueueFrame(false)); +- m_renderingFrames.ReleaseBuffers(); +- RestoreFB(); +- delete m_outputBuffers; +- m_outputBuffers = NULL; +- } +- +- /* Free extramem */ +- if (m_extraMem != NULL) +- { +- for (i = 0; i < m_vpuFrameBufferNum; i++) +- { +- if (m_extraMem[i].nSize > 0) +- { +- ret = VPU_DecFreeMem(&m_extraMem[i]); +- if (ret != VPU_DEC_RET_SUCCESS) +- { +- CLog::Log(LOGERROR, "%s - Release extra mem failed with error code %d.\n", __FUNCTION__, ret); +- } +- m_extraMem[i].nSize = 0; +- } +- } +- delete m_extraMem; +- m_extraMem = NULL; +- } + m_vpuFrameBufferNum = 0; + + if (m_vpuFrameBuffers != NULL) +@@ -1174,13 +494,10 @@ void CDVDVideoCodecIMX::Dispose(void) + m_tsm = NULL; + } + +- if (m_convert_bitstream) ++ if (m_converter) + { +- if (m_sps_pps_context.sps_pps_data) +- { +- free(m_sps_pps_context.sps_pps_data); +- m_sps_pps_context.sps_pps_data = NULL; +- } ++ m_converter->Close(); ++ SAFE_DELETE(m_converter); + } + return; + } +@@ -1190,12 +507,10 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + VpuDecFrameLengthInfo frameLengthInfo; + VpuBufferNode inData; + VpuDecRetCode ret; +- VpuDecOutFrameInfo frameInfo; + int decRet = 0; + int retStatus = 0; + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; +- bool bitstream_convered = false; + bool retry = false; + + #ifdef IMX_PROFILE +@@ -1211,8 +526,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } + + #ifdef IMX_PROFILE +- current = get_time(); +- CLog::Log(LOGDEBUG, "%s - delta time decode : %llu - demux size : %d dts : %f - pts : %f\n", __FUNCTION__, current - previous, iSize, dts, pts); ++ CLog::Log(LOGDEBUG, "%s - delta time decode : %llu - demux size : %d dts : %f - pts : %f\n", __FUNCTION__, -1, iSize, dts, pts); + previous = current; + #endif + +@@ -1221,28 +535,18 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + ((unsigned int *)pData)[0] = htonl(iSize-4); + */ + +- while (VpuDeQueueFrame(false)); +- + if (pData && iSize) + { + if (m_convert_bitstream) + { + // convert demuxer packet from bitstream to bytestream (AnnexB) +- int bytestream_size = 0; +- uint8_t *bytestream_buff = NULL; +- +- if (!bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size)) +- { +- CLog::Log(LOGERROR, "%s - bitstream convert error...\n", __FUNCTION__); +- return VC_ERROR; +- } +- +- if (bytestream_buff && (bytestream_size > 0)) ++ if (m_converter->Convert(demuxer_content, demuxer_bytes)) + { +- bitstream_convered = true; +- demuxer_bytes = bytestream_size; +- demuxer_content = bytestream_buff; ++ demuxer_content = m_converter->GetConvertBuffer(); ++ demuxer_bytes = m_converter->GetConvertSize(); + } ++ else ++ CLog::Log(LOGERROR,"%s - bitstream_convert error", __FUNCTION__); + } + + if (pts != DVD_NOPTS_VALUE) +@@ -1291,11 +595,11 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + retry = false; + #ifdef IMX_PROFILE +- before_dec = get_time(); ++ //before_dec = get_time(); + #endif + 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, get_time() - before_dec); ++ CLog::Log(LOGDEBUG, "%s - VPU dec 0x%x decode takes : %lld\n\n", __FUNCTION__, decRet, -1); + #endif + + if (ret != VPU_DEC_RET_SUCCESS) +@@ -1354,16 +658,13 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + if (retStatus & VC_PICTURE) + CLog::Log(LOGERROR, "%s - Second picture in the same decode call !\n", __FUNCTION__); + +- ret = VPU_DecGetOutputFrame(m_vpuHandle, &frameInfo); ++ 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; + } +- if (VpuPushFrame(&frameInfo)) +- { +- retStatus |= VC_PICTURE; +- } ++ retStatus |= VC_PICTURE; + } //VPU_DEC_OUTPUT_DIS + + if (decRet & VPU_DEC_OUTPUT_REPEAT) +@@ -1425,35 +726,17 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } while (retry == true); + } //(pData && iSize) + +- if (GetAvailableBufferNb() > (m_vpuFrameBufferNum - m_extraVpuBuffers)) ++ if (retStatus == 0) + { + retStatus |= VC_BUFFER; + } +- else +- { +- if (retStatus == 0) { +- /* No Picture ready and Not enough VPU buffers. It should NOT happen so log dedicated error */ +- CLog::Log(LOGERROR, "%s - Not hw buffer available. Waiting for 2ms\n", __FUNCTION__); +- /* Lets wait for the IPU to free a buffer. Anyway we have several decoded frames ready */ +- usleep(2000); +- } +- } +- +- if (bitstream_convered) +- free(demuxer_content); +- +- retStatus &= (~VC_PICTURE); +- if (m_decodedFrames.size() >= IMX_MAX_QUEUE_SIZE) +- retStatus |= VC_PICTURE; + + #ifdef IMX_PROFILE +- CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, get_time() - previous); ++ CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, -1); + #endif + return retStatus; + + out_error: +- if (bitstream_convered) +- free(demuxer_content); + return VC_ERROR; + } + +@@ -1466,9 +749,6 @@ void CDVDVideoCodecIMX::Reset() + /* We have to resync timestamp manager */ + m_tsSyncRequired = true; + +- /* Flush decoded frames */ +- FlushDecodedFrames(); +- + /* Flush VPU */ + ret = VPU_DecFlushAll(m_vpuHandle); + if (ret != VPU_DEC_RET_SUCCESS) +@@ -1480,80 +760,61 @@ void CDVDVideoCodecIMX::Reset() + + unsigned CDVDVideoCodecIMX::GetAllowedReferences() + { +- // Note : It is useless if CLinuxRendererGLES::GetProcessorSize returns 0 for RENDER_FMT_IMX +- return min(3, m_extraVpuBuffers / 2); ++ return 3; + } + +- +-bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) ++bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) + { +- double currentPlayerPts; +- double ts = DVD_NOPTS_VALUE; +- DVDVideoPicture DVDFrame; +- +- if (m_decodedFrames.size() == 0) +- { +- CLog::Log(LOGERROR, "%s called while no picture ready\n", __FUNCTION__); +- return false; +- } +- +- /* Retrieve oldest decoded frame */ +- DVDFrame = m_decodedFrames.front(); +- m_decodedFrames.pop(); +- //CLog::Log(LOGNOTICE, "%s - buffer(%d)\n", __FUNCTION__, DVDFrame.imxOutputFrame->v4l2BufferIdx); +- +- pDvdVideoPicture->iFlags &= DVP_FLAG_DROPPED; +- if ((pDvdVideoPicture->iFlags != 0) || (m_dropState)) ++ if (pDvdVideoPicture) + { +- CLog::Log(LOGNOTICE, "%s - Flushing video picture\n", __FUNCTION__); +- pDvdVideoPicture->iFlags = DVP_FLAG_DROPPED; +- VpuReleaseBufferV4L(DVDFrame.imxOutputFrame->v4l2BufferIdx); +- DVDFrame.imxOutputFrame = NULL; +- } +- else +- { +- ts = DVDFrame.pts; +- currentPlayerPts = GetPlayerPtsSeconds() * (double)DVD_TIME_BASE; +- if (currentPlayerPts > ts) ++ //clear frame display flag ++ VpuDecRetCode ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf); ++ if(ret != VPU_DEC_RET_SUCCESS) + { +- CLog::Log(LOGERROR, "%s - player is ahead of time (%f)\n", __FUNCTION__, currentPlayerPts - ts); ++ CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); ++ return false; + } +- //CLog::Log(LOGINFO, "%s - idx : %d - delta call %f - delta ts %f \n", __FUNCTION__, outputFrame.v4l2_buffer->index,ts - previous, ts - currentPlayerPts); + } + +-#ifdef NO_V4L_RENDERING +- if (!m_dropState) +- { +- VpuReleaseBufferV4L(DVDFrame.imxOutputFrame->v4l2BufferIdx); +- } +-#endif ++ return true; ++} ++ ++bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) ++{ ++ pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; ++ if (m_dropState) ++ pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; ++ else ++ pDvdVideoPicture->iFlags &= ~DVP_FLAG_DROPPED; + +- pDvdVideoPicture->pts = DVDFrame.pts; ++ pDvdVideoPicture->pts = (double)TSManagerSend(m_tsm) / (double)1000.0; + if (!m_usePTS) + { + pDvdVideoPicture->pts = DVD_NOPTS_VALUE; + } +- pDvdVideoPicture->dts = DVDFrame.dts; +- pDvdVideoPicture->iWidth = DVDFrame.iWidth; +- pDvdVideoPicture->iHeight = DVDFrame.iHeight; ++ 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; + if (m_dropState) + { +- pDvdVideoPicture->iDisplayWidth = DVDFrame.iWidth; +- pDvdVideoPicture->iDisplayHeight = DVDFrame.iHeight; ++ pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth; ++ pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + } + else + { +- pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * DVDFrame.imxOutputFrame->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; ++ pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; + pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + } +- pDvdVideoPicture->format = DVDFrame.format; +- pDvdVideoPicture->imxOutputFrame = DVDFrame.imxOutputFrame; ++ pDvdVideoPicture->format = RENDER_FMT_YUV420P; ++ pDvdVideoPicture->iLineSize[0] = m_frameInfo.pDisplayFrameBuf->nStrideY; ++ pDvdVideoPicture->iLineSize[1] = m_frameInfo.pDisplayFrameBuf->nStrideC; ++ pDvdVideoPicture->iLineSize[2] = m_frameInfo.pDisplayFrameBuf->nStrideC; ++ pDvdVideoPicture->iLineSize[3] = 0; ++ pDvdVideoPicture->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; ++ pDvdVideoPicture->data[1] = m_frameInfo.pDisplayFrameBuf->pbufVirtCb; ++ pDvdVideoPicture->data[2] = m_frameInfo.pDisplayFrameBuf->pbufVirtCr; ++ pDvdVideoPicture->data[3] = 0; + +-#ifdef V4L_OUTPUT_PROFILE +- CLog::Log(LOGDEBUG, "%s - QF : %d - HWfre : %d/%d/%d\n", +- (int)m_decodedFrames.size(), GetAvailableBufferNb(), +- m_extraVpuBuffers, m_vpuFrameBufferNum); +-#endif + return true; + } + +@@ -1570,168 +831,3 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) + CLog::Log(LOGNOTICE, "%s : %d\n", __FUNCTION__, bDrop); + } + } +- +-/* bitstream convert : Shameless copy from openmax */ +-/* TODO : Have a look at it as the malloc/copy/free strategy is obviously not the most efficient one */ +- +-bool CDVDVideoCodecIMX::bitstream_convert_init(void *in_extradata, int in_extrasize) +-{ +- // based on h264_mp4toannexb_bsf.c (ffmpeg) +- // which is Copyright (c) 2007 Benoit Fouet +- // and Licensed GPL 2.1 or greater +- +- m_sps_pps_size = 0; +- m_sps_pps_context.sps_pps_data = NULL; +- +- // nothing to filter +- if (!in_extradata || in_extrasize < 6) +- return false; +- +- uint16_t unit_size; +- uint32_t total_size = 0; +- uint8_t *out = NULL, unit_nb, sps_done = 0; +- const uint8_t *extradata = (uint8_t*)in_extradata + 4; +- static const uint8_t nalu_header[4] = {0, 0, 0, 1}; +- +- // retrieve length coded size +- m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1; +- if (m_sps_pps_context.length_size == 3) +- return false; +- +- // retrieve sps and pps unit(s) +- unit_nb = *extradata++ & 0x1f; // number of sps unit(s) +- if (!unit_nb) +- { +- unit_nb = *extradata++; // number of pps unit(s) +- sps_done++; +- } +- while (unit_nb--) +- { +- unit_size = extradata[0] << 8 | extradata[1]; +- total_size += unit_size + 4; +- if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) ) +- { +- free(out); +- return false; +- } +- uint8_t* new_out = (uint8_t*)realloc(out, total_size); +- if (new_out) +- { +- out = new_out; +- } +- else +- { +- CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out", __FUNCTION__); +- free(out); +- return false; +- } +- +- memcpy(out + total_size - unit_size - 4, nalu_header, 4); +- memcpy(out + total_size - unit_size, extradata + 2, unit_size); +- extradata += 2 + unit_size; +- +- if (!unit_nb && !sps_done++) +- unit_nb = *extradata++; // number of pps unit(s) +- } +- +- m_sps_pps_context.sps_pps_data = out; +- m_sps_pps_context.size = total_size; +- m_sps_pps_context.first_idr = 1; +- +- return true; +-} +- +-bool CDVDVideoCodecIMX::bitstream_convert(BYTE* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size) +-{ +- // based on h264_mp4toannexb_bsf.c (ffmpeg) +- // which is Copyright (c) 2007 Benoit Fouet +- // and Licensed GPL 2.1 or greater +- +- uint8_t *buf = pData; +- uint32_t buf_size = iSize; +- uint8_t unit_type; +- int32_t nal_size; +- uint32_t cumul_size = 0; +- const uint8_t *buf_end = buf + buf_size; +- +- do +- { +- if (buf + m_sps_pps_context.length_size > buf_end) +- goto fail; +- +- if (m_sps_pps_context.length_size == 1) +- nal_size = buf[0]; +- else if (m_sps_pps_context.length_size == 2) +- nal_size = buf[0] << 8 | buf[1]; +- else +- nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +- +- // FIXME CLog::Log(LOGERROR, "%s - nal_size : %d \n", __FUNCTION__, nal_size); +- buf += m_sps_pps_context.length_size; +- unit_type = *buf & 0x1f; +- +- if (buf + nal_size > buf_end || nal_size < 0) +- goto fail; +- +- // prepend only to the first type 5 NAL unit of an IDR picture +- if (m_sps_pps_context.first_idr && unit_type == 5) +- { +- bitstream_alloc_and_copy(poutbuf, poutbuf_size, +- m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size); +- m_sps_pps_context.first_idr = 0; +- } +- else +- { +- bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size); +- if (!m_sps_pps_context.first_idr && unit_type == 1) +- m_sps_pps_context.first_idr = 1; +- } +- +- buf += nal_size; +- cumul_size += nal_size + m_sps_pps_context.length_size; +- } while (cumul_size < buf_size); +- +- return true; +- +-fail: +- free(*poutbuf); +- *poutbuf = NULL; +- *poutbuf_size = 0; +- return false; +-} +- +-void CDVDVideoCodecIMX::bitstream_alloc_and_copy( +- uint8_t **poutbuf, int *poutbuf_size, +- const uint8_t *sps_pps, uint32_t sps_pps_size, +- const uint8_t *in, uint32_t in_size) +-{ +- // based on h264_mp4toannexb_bsf.c (ffmpeg) +- // which is Copyright (c) 2007 Benoit Fouet +- // and Licensed GPL 2.1 or greater +- +- #define CHD_WB32(p, d) { \ +- ((uint8_t*)(p))[3] = (d); \ +- ((uint8_t*)(p))[2] = (d) >> 8; \ +- ((uint8_t*)(p))[1] = (d) >> 16; \ +- ((uint8_t*)(p))[0] = (d) >> 24; } +- +- uint32_t offset = *poutbuf_size; +- uint8_t nal_header_size = offset ? 3 : 4; +- +- *poutbuf_size += sps_pps_size + in_size + nal_header_size; +- *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size); +- if (sps_pps) +- memcpy(*poutbuf + offset, sps_pps, sps_pps_size); +- +- memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size); +- if (!offset) +- { +- CHD_WB32(*poutbuf + sps_pps_size, 1); +- } +- else +- { +- (*poutbuf + offset + sps_pps_size)[0] = 0; +- (*poutbuf + offset + sps_pps_size)[1] = 0; +- (*poutbuf + offset + sps_pps_size)[2] = 1; +- } +-} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index d72b899..cc0f26c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -24,6 +24,7 @@ + #include "DVDVideoCodec.h" + #include "DVDStreamInfo.h" + #include "threads/CriticalSection.h" ++#include "utils/BitstreamConverter.h" + + + //#define IMX_PROFILE +@@ -44,54 +45,6 @@ typedef struct + unsigned int phyMem_size[VPU_DEC_MAX_NUM_MEM_NUM]; + } DecMemInfo; + +-/* Output frame properties */ +-struct CIMXOutputFrame { +- // Render a picture. Calls RenderingFrames.Queue +- void Render(struct v4l2_crop &); +- // Clear a picture by settings the frameNo to "expired" +- void Release() { frameNo = 0; } +- +- int v4l2BufferIdx; +- VpuFieldType field; +- VpuRect picCrop; +- unsigned int nQ16ShiftWidthDivHeightRatio; +- int frameNo; +-#ifdef IMX_PROFILE +- unsigned long long pushTS; +-#endif +-}; +- +-class CIMXRenderingFrames +-{ +-public: +- static CIMXRenderingFrames& GetInstance(); +- bool AllocateBuffers(const struct v4l2_format *, int); +- void *GetVirtAddr(int idx); +- void *GetPhyAddr(int idx); +- void ReleaseBuffers(); +- int FindBuffer(void *); +- int DeQueue(bool wait); +- void Queue(CIMXOutputFrame *, struct v4l2_crop &); +- +-private: +- CIMXRenderingFrames(); +- void __ReleaseBuffers(); +- +- static const char *m_v4lDeviceName; // V4L2 device Name +- static CIMXRenderingFrames* m_instance; // Unique instance of the class +- +- CCriticalSection m_renderingFramesLock; // Lock to ensure multithreading safety for class fields +- bool m_ready; // Buffers are allocated and frames can be Queued/Dequeue +- int m_v4lfd; // fd on V4L2 device +- struct v4l2_buffer *m_v4lBuffers; // Table of V4L buffer info (as returned by VIDIOC_QUERYBUF) +- int m_bufferNum; // Number of allocated V4L2 buffers +- struct v4l2_crop m_crop; // Current cropping properties +- bool m_streamOn; // Flag that indicates whether streaming in on (from V4L point of view) +- int m_pushedFrames; // Number of frames queued in V4L2 +- void **m_virtAddr; // Table holding virtual adresses of mmaped V4L2 buffers +- int m_motionCtrl; // Current motion control algo +-}; +- + class CDVDVideoCodecIMX : public CDVDVideoCodec + { + public: +@@ -103,6 +56,7 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + 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; } +@@ -114,38 +68,9 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + bool VpuAllocBuffers(VpuMemInfo *); + bool VpuFreeBuffers(void); + bool VpuAllocFrameBuffers(void); +- bool VpuPushFrame(VpuDecOutFrameInfo*); +- bool VpuDeQueueFrame(bool); +- int GetAvailableBufferNb(void); +- void InitFB(void); +- void RestoreFB(void); +- void FlushDecodedFrames(void); +- bool VpuReleaseBufferV4L(int); +- +- /* Helper structure which holds a queued output frame +- * and its associated decoder frame buffer.*/ +- struct VpuV4LFrameBuffer +- { +- // Returns whether the buffer is currently used (associated) +- bool used() const { return buffer != NULL; } +- int frameNo() const { return outputFrame.frameNo; } +- bool expired(int frameNo) const +- { return (buffer != NULL) && (outputFrame.frameNo < frameNo); } +- // Associate a VPU frame buffer +- void store(VpuFrameBuffer *b, int frameNo) { +- buffer = b; +- outputFrame.frameNo = frameNo; +- } +- // Reset the state +- void clear() { store(NULL, 0); } +- +- VpuFrameBuffer *buffer; +- CIMXOutputFrame outputFrame; +- }; + + static const int m_extraVpuBuffers; // Number of additional buffers for VPU + +- CIMXRenderingFrames&m_renderingFrames; // The global RenderingFrames instance + 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 +@@ -158,34 +83,11 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + int m_vpuFrameBufferNum; // Total number of allocated frame buffers + VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description + VpuMemDesc *m_extraMem; // Table of allocated extra Memory +- VpuV4LFrameBuffer *m_outputBuffers; // Table of V4L buffers out of VPU (index is V4L buf index) (used to call properly VPU_DecOutFrameDisplayed) +- std::queue m_decodedFrames; // Decoded Frames ready to be retrieved by GetPicture ++// VpuMemDesc *m_outputBuffers; // Table of buffers out of VPU (used to call properly VPU_DecOutFrameDisplayed) + int m_frameCounter; // Decoded frames counter + bool m_usePTS; // State whether pts out of decoding process should be used +- +- /* FIXME : Rework is still required for fields below this line */ +- +- /* create a real class and share with openmax ? */ +- // bitstream to bytestream (Annex B) conversion support. +- bool bitstream_convert_init(void *in_extradata, int in_extrasize); +- bool bitstream_convert(BYTE* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size); +- static void bitstream_alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size, +- const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size); +- typedef struct omx_bitstream_ctx { +- uint8_t length_size; +- uint8_t first_idr; +- uint8_t *sps_pps_data; +- uint32_t size; +- omx_bitstream_ctx() +- { +- length_size = 0; +- first_idr = 0; +- sps_pps_data = NULL; +- size = 0; +- } +- } omx_bitstream_ctx; +- uint32_t m_sps_pps_size; +- omx_bitstream_ctx m_sps_pps_context; +- bool m_convert_bitstream; ++ VpuDecOutFrameInfo m_frameInfo; ++ CBitstreamConverter *m_converter; ++ bool m_convert_bitstream; + + }; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 9ce20dd..99b3155 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -994,7 +994,6 @@ static std::string GetRenderFormatName(ERenderFormat format) + case RENDER_FMT_CVBREF: return "BGRA"; + case RENDER_FMT_EGLIMG: return "EGLIMG"; + case RENDER_FMT_BYPASS: return "BYPASS"; +- case RENDER_FMT_IMX: return "IMX"; + case RENDER_FMT_MEDIACODEC:return "MEDIACODEC"; + case RENDER_FMT_NONE: return "NONE"; + } +diff --git a/xbmc/windowing/egl/EGLWrapper.cpp b/xbmc/windowing/egl/EGLWrapper.cpp +index 0726cc2..717b369 100644 +--- a/xbmc/windowing/egl/EGLWrapper.cpp ++++ b/xbmc/windowing/egl/EGLWrapper.cpp +@@ -17,7 +17,6 @@ + * . + * + */ +-#include "EGLNativeTypeIMX.h" + #include "system.h" + + #ifdef HAS_EGL +@@ -26,6 +25,9 @@ + #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); +@@ -82,8 +84,11 @@ bool CEGLWrapper::Initialize(const std::string &implementation) + if ((nativeGuess = CreateEGLNativeType(implementation)) || + (nativeGuess = CreateEGLNativeType(implementation)) || + (nativeGuess = CreateEGLNativeType(implementation)) || +- (nativeGuess = CreateEGLNativeType(implementation)) || +- (nativeGuess = CreateEGLNativeType(implementation))) ++ (nativeGuess = CreateEGLNativeType(implementation)) ++#ifdef HAS_IMXVPU ++ || (nativeGuess = CreateEGLNativeType(implementation)) ++#endif ++ ) + { + m_nativeTypes = nativeGuess; + +diff --git a/xbmc/windowing/egl/Makefile.in b/xbmc/windowing/egl/Makefile.in +index f59f9cb..85abb44 100644 +--- a/xbmc/windowing/egl/Makefile.in ++++ b/xbmc/windowing/egl/Makefile.in +@@ -5,7 +5,6 @@ SRCS+= EGLNativeTypeAmlogic.cpp + SRCS+= EGLNativeTypeAndroid.cpp + SRCS+= EGLNativeTypeRaspberryPI.cpp + SRCS+= EGLNativeTypeWayland.cpp +-SRCS+= EGLNativeTypeIMX.cpp + SRCS+= EGLWrapper.cpp + + # Wayland specific detail +@@ -25,6 +24,10 @@ SRCS+= wayland/Callback.cpp \ + wayland/XBMCSurface.cpp + endif + ++ifeq (@USE_IMXVPU@,1) ++SRCS+= EGLNativeTypeIMX.cpp ++endif ++ + LIB = windowing_egl.a + + include ../../../Makefile.include +-- +1.9.3 + + +From a29b91502d109417b0eb8d6ff97d8b56aa056bc9 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Tue, 11 Feb 2014 13:42:53 +0100 +Subject: [PATCH 03/56] CHG: [IMX] baseline direct buffer rendering + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 107 ++++++++++++++++++++- + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 5 + + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 2 + + .../VideoRenderers/VideoShaders/YUV2RGBShader.cpp | 14 +-- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 6 ++ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 66 ++++++++++--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 19 ++++ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h | 37 +++++++ + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + + 10 files changed, 232 insertions(+), 26 deletions(-) + create mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 72eb725..bc3a39f 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -103,6 +103,7 @@ CLinuxRendererGLES::YUVBUFFER::YUVBUFFER() + #if defined(TARGET_ANDROID) + mediacodec = NULL; + #endif ++ codecinfo = NULL; + } + + CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER() +@@ -604,6 +605,7 @@ unsigned int CLinuxRendererGLES::PreInit() + #if defined(TARGET_ANDROID) + m_formats.push_back(RENDER_FMT_MEDIACODEC); + #endif ++ m_formats.push_back(RENDER_FMT_YV12_BUFFER); + + // setup the background colour + m_clearColour = (float)(g_advancedSettings.m_videoBlackBarColour & 0xff) / 0xff; +@@ -711,6 +713,10 @@ void CLinuxRendererGLES::LoadShaders(int field) + 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_BYPASS) + { + CLog::Log(LOGNOTICE, "GL: Using BYPASS render method"); +@@ -803,6 +809,12 @@ void CLinuxRendererGLES::LoadShaders(int field) + 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 + { + // default to YV12 texture handlers +@@ -1158,7 +1170,7 @@ void CLinuxRendererGLES::RenderMultiPass(int index, int field) + // imgwidth *= planes[0].pixpertex_x; + // imgheight *= planes[0].pixpertex_y; + // } +-// ++// + // glBegin(GL_QUADS); + // + // glMultiTexCoord2fARB(GL_TEXTURE0, planes[0].rect.x1, planes[0].rect.y1); +@@ -2301,7 +2313,7 @@ bool CLinuxRendererGLES::CreateCVRefTexture(int index) + + 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); +@@ -2407,7 +2419,7 @@ bool CLinuxRendererGLES::CreateEGLIMGTexture(int index) + + 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); + +@@ -2481,6 +2493,84 @@ bool CLinuxRendererGLES::CreateSurfaceTexture(int index) + 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 ; iLock(); ++} ++ + #endif + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index 642cded..e39a93f 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -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; + +@@ -170,6 +171,7 @@ class CLinuxRendererGLES : public CBaseRenderer + // mediaCodec + virtual void AddProcessor(CDVDMediaCodecInfo *mediacodec, int index); + #endif ++ virtual void AddProcessor(CDVDVideoCodecBuffer *codecinfo, int index); + + protected: + virtual void Render(DWORD flags, int index); +@@ -209,6 +211,8 @@ class CLinuxRendererGLES : public CBaseRenderer + void DeleteSurfaceTexture(int index); + bool CreateSurfaceTexture(int index); + ++ void UploadYV12BufferTexture(int index); ++ + void CalculateTextureSourceRects(int source, int num_planes); + + // renderers +@@ -285,6 +289,7 @@ class CLinuxRendererGLES : public CBaseRenderer + // mediacodec + CDVDMediaCodecInfo *mediacodec; + #endif ++ CDVDVideoCodecBuffer *codecinfo; + }; + + typedef YUVBUFFER YUVBUFFERS[NUM_BUFFERS]; +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index f15e80d..384bcd6 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -37,6 +37,7 @@ enum ERenderFormat { + RENDER_FMT_BYPASS, + RENDER_FMT_EGLIMG, + RENDER_FMT_MEDIACODEC, ++ RENDER_FMT_YV12_BUFFER, + }; + + #endif +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 6832721..1079ff4 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -930,6 +930,8 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + else if(pic.format == RENDER_FMT_MEDIACODEC) + m_pRenderer->AddProcessor(pic.mediacodec, index); + #endif ++ else if(pic.format == RENDER_FMT_YV12_BUFFER) ++ m_pRenderer->AddProcessor(pic.codecinfo, index); + + m_pRenderer->ReleaseImage(index, false); + +diff --git a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +index 21a4ee2..7e82149 100644 +--- a/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp ++++ b/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp +@@ -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 @@ static float yuv_coef_bt709[4][4] = + { 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 yuv_coef_smtp240m[4][4] = + 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 @@ BaseYUV2RGBGLSLShader::BaseYUV2RGBGLSLShader(bool rect, unsigned flags, ERenderF + 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 --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +index 1553789..760c264 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h +@@ -25,6 +25,7 @@ + #include + #include + #include "cores/VideoRenderers/RenderFormats.h" ++#include "DVDVideoCodecInfo.h" + + extern "C" { + #include "libavcodec/avcodec.h" +@@ -93,6 +94,11 @@ struct DVDVideoPicture + struct { + CDVDMediaCodecInfo *mediacodec; + }; ++ ++ struct { ++ CDVDVideoCodecBuffer *codecinfo; ++ }; ++ + }; + + unsigned int iFlags; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 9adffd3..6f29357 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -316,6 +316,8 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + { + m_usePTS = false; + } ++ m_converter = NULL; ++ m_convert_bitstream = false; + } + + CDVDVideoCodecIMX::~CDVDVideoCodecIMX() +@@ -767,13 +769,7 @@ bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) + { + if (pDvdVideoPicture) + { +- //clear frame display flag +- VpuDecRetCode ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf); +- if(ret != VPU_DEC_RET_SUCCESS) +- { +- CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); +- return false; +- } ++ SAFE_RELEASE(pDvdVideoPicture->codecinfo); + } + + return true; +@@ -805,15 +801,18 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; + pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + } +- pDvdVideoPicture->format = RENDER_FMT_YUV420P; +- pDvdVideoPicture->iLineSize[0] = m_frameInfo.pDisplayFrameBuf->nStrideY; +- pDvdVideoPicture->iLineSize[1] = m_frameInfo.pDisplayFrameBuf->nStrideC; +- pDvdVideoPicture->iLineSize[2] = m_frameInfo.pDisplayFrameBuf->nStrideC; +- pDvdVideoPicture->iLineSize[3] = 0; +- pDvdVideoPicture->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; +- pDvdVideoPicture->data[1] = m_frameInfo.pDisplayFrameBuf->pbufVirtCb; +- pDvdVideoPicture->data[2] = m_frameInfo.pDisplayFrameBuf->pbufVirtCr; +- pDvdVideoPicture->data[3] = 0; ++ ++ pDvdVideoPicture->format = RENDER_FMT_YV12_BUFFER; ++ ++ pDvdVideoPicture->codecinfo = new CDVDVideoCodecIMXBuffer(m_vpuHandle, m_frameInfo); ++ pDvdVideoPicture->codecinfo->iLineSize[0] = m_frameInfo.pDisplayFrameBuf->nStrideY; ++ pDvdVideoPicture->codecinfo->iLineSize[1] = m_frameInfo.pDisplayFrameBuf->nStrideC; ++ pDvdVideoPicture->codecinfo->iLineSize[2] = m_frameInfo.pDisplayFrameBuf->nStrideC; ++ pDvdVideoPicture->codecinfo->iLineSize[3] = 0; ++ pDvdVideoPicture->codecinfo->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; ++ pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufVirtCb; ++ pDvdVideoPicture->codecinfo->data[2] = m_frameInfo.pDisplayFrameBuf->pbufVirtCr; ++ pDvdVideoPicture->codecinfo->data[3] = 0; + + return true; + } +@@ -831,3 +830,38 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) + CLog::Log(LOGNOTICE, "%s : %d\n", __FUNCTION__, bDrop); + } + } ++ ++/*******************************************/ ++ ++CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(VpuDecHandle handle, VpuDecOutFrameInfo frameInfo) ++ : m_refs(1) ++ , m_vpuHandle(handle) ++ , m_frameInfo(frameInfo) ++{ ++} ++ ++void CDVDVideoCodecIMXBuffer::Lock() ++{ ++ AtomicIncrement(&m_refs); ++} ++ ++long CDVDVideoCodecIMXBuffer::Release() ++{ ++ long count = AtomicDecrement(&m_refs); ++ if (count == 0) ++ { ++ VpuDecRetCode ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf); ++ if(ret != VPU_DEC_RET_SUCCESS) ++ { ++ CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); ++ } ++ delete this; ++ } ++ ++ return count; ++} ++ ++CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() ++{ ++ assert(m_refs == 0); ++} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index cc0f26c..1531bd8 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -23,6 +23,7 @@ + #include + #include "DVDVideoCodec.h" + #include "DVDStreamInfo.h" ++#include "DVDVideoCodecInfo.h" + #include "threads/CriticalSection.h" + #include "utils/BitstreamConverter.h" + +@@ -45,6 +46,24 @@ typedef struct + unsigned int phyMem_size[VPU_DEC_MAX_NUM_MEM_NUM]; + } DecMemInfo; + ++class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer ++{ ++public: ++ CDVDVideoCodecIMXBuffer(VpuDecHandle handle, VpuDecOutFrameInfo frameInfo); ++ ++ // reference counting ++ virtual void Lock(); ++ virtual long Release(); ++ ++protected: ++ // private because we are reference counted ++ virtual ~CDVDVideoCodecIMXBuffer(); ++ ++ long m_refs; ++ VpuDecHandle m_vpuHandle; // Handle for VPU library calls ++ VpuDecOutFrameInfo m_frameInfo; ++}; ++ + class CDVDVideoCodecIMX : public CDVDVideoCodec + { + public: +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h +new file mode 100644 +index 0000000..18078d3 +--- /dev/null ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h +@@ -0,0 +1,37 @@ ++/* ++ * 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 ++ * . ++ * ++ */ ++ ++#ifndef DVDVIDEOCODECINFO_H ++#define DVDVIDEOCODECINFO_H ++ ++#include "cores/VideoRenderers/RenderFormats.h" ++ ++class CDVDVideoCodecBuffer ++{ ++public: ++ // reference counting ++ virtual void Lock() = 0; ++ virtual long Release() = 0; ++ ++ uint8_t* data[4]; // [4] = alpha channel, currently not used ++ int iLineSize[4]; // [4] = alpha channel, currently not used ++}; ++ ++#endif // DVDVIDEOCODECINFO_H +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index 99b3155..a823b69 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -995,6 +995,7 @@ static std::string GetRenderFormatName(ERenderFormat format) + 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_NONE: return "NONE"; + } + return "UNKNOWN"; +-- +1.9.3 + + +From bf6fadeccef83b7a9e7a0f615a78979244e4bfeb Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Thu, 13 Feb 2014 17:43:23 +0100 +Subject: [PATCH 04/56] ADD: [imx] direct texture rendering + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 171 +++++++++++++++++++++ + xbmc/cores/VideoRenderers/LinuxRendererGLES.h | 8 +- + xbmc/cores/VideoRenderers/RenderFormats.h | 1 + + xbmc/cores/VideoRenderers/RenderManager.cpp | 2 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 80 ++++------ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 8 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h | 5 +- + xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 49 +----- + 9 files changed, 224 insertions(+), 101 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index bc3a39f..0c8b357 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -79,6 +79,12 @@ static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; + static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + #endif + ++#ifdef HAS_IMXVPU ++// GLES extension functions ++#include ++#include ++#endif ++ + #if defined(TARGET_ANDROID) + #include "DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h" + #endif +@@ -280,6 +286,10 @@ int CLinuxRendererGLES::GetImage(YV12Image *image, int source, bool readonly) + { + return source; + } ++ if ( m_renderMethod & RENDER_IMXMAP ) ++ { ++ return source; ++ } + + #ifdef HAVE_VIDEOTOOLBOXDECODER + if (m_renderMethod & RENDER_CVREF ) +@@ -606,6 +616,9 @@ unsigned int CLinuxRendererGLES::PreInit() + 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; +@@ -717,6 +730,12 @@ void CLinuxRendererGLES::LoadShaders(int field) + { + 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"); +@@ -815,6 +834,12 @@ void CLinuxRendererGLES::LoadShaders(int field) + 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 +@@ -966,6 +991,10 @@ void CLinuxRendererGLES::Render(DWORD flags, int index) + { + RenderSurfaceTexture(index, m_currentField); + } ++ else if (m_renderMethod & RENDER_IMXMAP) ++ { ++ RenderIMXMAPTexture(index, m_currentField); ++ } + else + { + RenderSoftware(index, m_currentField); +@@ -1592,6 +1621,72 @@ void CLinuxRendererGLES::RenderCoreVideoRef(int index, int field) + #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]; ++ ++ 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(); ++ ++#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) +@@ -2600,6 +2695,82 @@ void CLinuxRendererGLES::SetTextureFilter(GLenum method) + } + } + ++//******************************************************************************************************** ++// IMXMAP creation, deletion, copying + clearing ++//******************************************************************************************************** ++void CLinuxRendererGLES::UploadIMXMAPTexture(int index) ++{ ++#ifdef HAS_IMXVPU ++ YUVBUFFER& buf = m_buffers[index]; ++ CDVDVideoCodecBuffer* codecinfo = buf.codecinfo; ++ ++ if(codecinfo && codecinfo->IsValid()) ++ { ++ YUVPLANE &plane = m_buffers[index].fields[0][0]; ++ ++ glActiveTexture(GL_TEXTURE0); ++ glBindTexture(m_textureTarget, plane.id); ++ ++ GLuint physical = ~0U; ++ glTexDirectVIVMap(m_textureTarget, codecinfo->iWidth, codecinfo->iHeight, GL_VIV_NV12, ++ (GLvoid **)(&codecinfo->data[0]), &physical); ++ glTexDirectInvalidateVIV(m_textureTarget); ++ ++ glBindTexture(m_textureTarget, 0); ++ ++ plane.flipindex = m_buffers[index].flipindex; ++ } ++ ++ YUVFIELDS &fields = m_buffers[index].fields; ++ YUVPLANE &plane = fields[0][0]; ++ plane.texwidth = codecinfo->iWidth; ++ plane.texheight = codecinfo->iHeight; ++ ++ CalculateTextureSourceRects(index, 1); ++#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; ++} ++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 +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +index e39a93f..e1916db 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h +@@ -90,7 +90,8 @@ enum RenderMethod + RENDER_CVREF = 0x080, + RENDER_BYPASS = 0x100, + RENDER_EGLIMG = 0x200, +- RENDER_MEDIACODEC = 0x400 ++ RENDER_MEDIACODEC = 0x400, ++ RENDER_IMXMAP = 0x800 + }; + + enum RenderQuality +@@ -213,6 +214,10 @@ class CLinuxRendererGLES : public CBaseRenderer + + void UploadYV12BufferTexture(int index); + ++ void UploadIMXMAPTexture(int index); ++ void DeleteIMXMAPTexture(int index); ++ bool CreateIMXMAPTexture(int index); ++ + void CalculateTextureSourceRects(int source, int num_planes); + + // renderers +@@ -223,6 +228,7 @@ class CLinuxRendererGLES : public CBaseRenderer + 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; + +diff --git a/xbmc/cores/VideoRenderers/RenderFormats.h b/xbmc/cores/VideoRenderers/RenderFormats.h +index 384bcd6..714619e 100644 +--- a/xbmc/cores/VideoRenderers/RenderFormats.h ++++ b/xbmc/cores/VideoRenderers/RenderFormats.h +@@ -38,6 +38,7 @@ enum ERenderFormat { + RENDER_FMT_EGLIMG, + RENDER_FMT_MEDIACODEC, + RENDER_FMT_YV12_BUFFER, ++ RENDER_FMT_IMXMAP, + }; + + #endif +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 1079ff4..836bcd1 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -930,7 +930,7 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + else if(pic.format == RENDER_FMT_MEDIACODEC) + m_pRenderer->AddProcessor(pic.mediacodec, index); + #endif +- else if(pic.format == RENDER_FMT_YV12_BUFFER) ++ else if(pic.format == RENDER_FMT_YV12_BUFFER || pic.format == RENDER_FMT_IMXMAP) + m_pRenderer->AddProcessor(pic.codecinfo, index); + + m_pRenderer->ReleaseImage(index, false); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 6f29357..7c5c26b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -43,6 +43,7 @@ + #define IMX_MAX_QUEUE_SIZE 1 + // 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 = IMX_MAX_QUEUE_SIZE + 6; ++VpuDecHandle CDVDVideoCodecIMX::m_vpuHandle = 0; + + bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + { +@@ -165,7 +166,7 @@ bool CDVDVideoCodecIMX::VpuOpen(void) + VpuAllocBuffers(&memInfo); + + m_decOpenParam.nReorderEnable = 1; +- m_decOpenParam.nChromaInterleave = 0; ++ m_decOpenParam.nChromaInterleave = 1; + m_decOpenParam.nMapType = 0; + m_decOpenParam.nTiled2LinearEnable = 0; + m_decOpenParam.nEnableFileMode = 0; +@@ -205,11 +206,9 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + int totalSize=0; + int mvSize=0; + int ySize=0; +- int uSize=0; +- int vSize=0; ++ int uvSize=0; + int yStride=0; +- int uStride=0; +- int vStride=0; ++ int uvStride=0; + unsigned char* ptr; + unsigned char* ptrVirt; + int nAlign; +@@ -227,24 +226,21 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + ySize=Align(m_initInfo.nPicWidth,FRAME_ALIGN)*Align(m_initInfo.nPicHeight,FRAME_ALIGN); + } + +- //4:2:0 for all video +- uStride=yStride/2; +- vStride=uStride; +- uSize=ySize/4; +- vSize=uSize; +- mvSize=uSize; ++ //NV12 for all video ++ uvStride=yStride; ++ uvSize=ySize/2; ++ mvSize=uvSize/2; + + nAlign=m_initInfo.nAddressAlignment; + if(nAlign>1) + { + ySize=Align(ySize,nAlign); +- uSize=Align(uSize,nAlign); +- vSize=Align(vSize,nAlign); ++ uvSize=Align(uvSize,nAlign); + } + + for (i = 0 ; i < m_vpuFrameBufferNum; i++) + { +- totalSize=(ySize+uSize+vSize+mvSize+nAlign)*1; ++ totalSize=(ySize+uvSize+mvSize+nAlign)*1; + + vpuMem.nSize=totalSize; + ret = VPU_DecGetMem(&vpuMem); +@@ -274,19 +270,19 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + + /* fill stride info */ + m_vpuFrameBuffers[i].nStrideY=yStride; +- m_vpuFrameBuffers[i].nStrideC=uStride; ++ m_vpuFrameBuffers[i].nStrideC=uvStride; + + /* fill phy addr*/ + m_vpuFrameBuffers[i].pbufY=ptr; + m_vpuFrameBuffers[i].pbufCb=ptr+ySize; +- m_vpuFrameBuffers[i].pbufCr=ptr+ySize+uSize; +- m_vpuFrameBuffers[i].pbufMvCol=ptr+ySize+uSize+vSize; ++ 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=ptrVirt+ySize+uSize; +- m_vpuFrameBuffers[i].pbufVirtMvCol=ptrVirt+ySize+uSize+vSize; ++ m_vpuFrameBuffers[i].pbufVirtCr=0; ++ m_vpuFrameBuffers[i].pbufVirtMvCol=ptrVirt+ySize+uvSize; + //ptrVirt+=ySize+uSize+vSize+mvSize; + + m_vpuFrameBuffers[i].pbufY_tilebot=0; +@@ -528,7 +524,8 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } + + #ifdef IMX_PROFILE +- CLog::Log(LOGDEBUG, "%s - delta time decode : %llu - demux size : %d dts : %f - pts : %f\n", __FUNCTION__, -1, iSize, dts, pts); ++ 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 + +@@ -597,11 +594,11 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + retry = false; + #ifdef IMX_PROFILE +- //before_dec = get_time(); ++ before_dec = XbmcThreads::SystemClockMillis(); + #endif + 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, -1); ++ 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) +@@ -734,7 +731,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } + + #ifdef IMX_PROFILE +- CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, -1); ++ CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, XbmcThreads::SystemClockMillis() - previous); + #endif + return retStatus; + +@@ -783,6 +780,7 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + else + pDvdVideoPicture->iFlags &= ~DVP_FLAG_DROPPED; + ++ pDvdVideoPicture->format = RENDER_FMT_IMXMAP; + pDvdVideoPicture->pts = (double)TSManagerSend(m_tsm) / (double)1000.0; + if (!m_usePTS) + { +@@ -791,28 +789,14 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + 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; +- if (m_dropState) +- { +- pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth; +- pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; +- } +- else +- { +- pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; +- pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; +- } +- +- pDvdVideoPicture->format = RENDER_FMT_YV12_BUFFER; ++ pDvdVideoPicture->iDisplayWidth = m_frameInfo.pExtInfo->FrmCropRect.nRight - m_frameInfo.pExtInfo->FrmCropRect.nLeft; ++ pDvdVideoPicture->iDisplayHeight = m_frameInfo.pExtInfo->FrmCropRect.nBottom - m_frameInfo.pExtInfo->FrmCropRect.nTop; + +- pDvdVideoPicture->codecinfo = new CDVDVideoCodecIMXBuffer(m_vpuHandle, m_frameInfo); +- pDvdVideoPicture->codecinfo->iLineSize[0] = m_frameInfo.pDisplayFrameBuf->nStrideY; +- pDvdVideoPicture->codecinfo->iLineSize[1] = m_frameInfo.pDisplayFrameBuf->nStrideC; +- pDvdVideoPicture->codecinfo->iLineSize[2] = m_frameInfo.pDisplayFrameBuf->nStrideC; +- pDvdVideoPicture->codecinfo->iLineSize[3] = 0; ++ pDvdVideoPicture->codecinfo = new CDVDVideoCodecIMXBuffer(m_frameInfo); ++ pDvdVideoPicture->codecinfo->iWidth = m_frameInfo.pExtInfo->nFrmWidth; ++ pDvdVideoPicture->codecinfo->iHeight = m_frameInfo.pExtInfo->nFrmHeight; + pDvdVideoPicture->codecinfo->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; +- pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufVirtCb; +- pDvdVideoPicture->codecinfo->data[2] = m_frameInfo.pDisplayFrameBuf->pbufVirtCr; +- pDvdVideoPicture->codecinfo->data[3] = 0; ++ pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufY; + + return true; + } +@@ -833,9 +817,8 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) + + /*******************************************/ + +-CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(VpuDecHandle handle, VpuDecOutFrameInfo frameInfo) ++CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(VpuDecOutFrameInfo frameInfo) + : m_refs(1) +- , m_vpuHandle(handle) + , m_frameInfo(frameInfo) + { + } +@@ -850,7 +833,7 @@ long CDVDVideoCodecIMXBuffer::Release() + long count = AtomicDecrement(&m_refs); + if (count == 0) + { +- VpuDecRetCode ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf); ++ VpuDecRetCode ret = VPU_DecOutFrameDisplayed(CDVDVideoCodecIMX::m_vpuHandle, m_frameInfo.pDisplayFrameBuf); + if(ret != VPU_DEC_RET_SUCCESS) + { + CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); +@@ -861,6 +844,11 @@ long CDVDVideoCodecIMXBuffer::Release() + return count; + } + ++bool CDVDVideoCodecIMXBuffer::IsValid() ++{ ++ return (CDVDVideoCodecIMX::m_vpuHandle != 0); ++} ++ + CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() + { + assert(m_refs == 0); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 1531bd8..5487bfe 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -49,23 +49,25 @@ typedef struct + class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + { + public: +- CDVDVideoCodecIMXBuffer(VpuDecHandle handle, VpuDecOutFrameInfo frameInfo); ++ CDVDVideoCodecIMXBuffer(VpuDecOutFrameInfo frameInfo); + + // reference counting + virtual void Lock(); + virtual long Release(); ++ virtual bool IsValid(); + + protected: + // private because we are reference counted + virtual ~CDVDVideoCodecIMXBuffer(); + + long m_refs; +- VpuDecHandle m_vpuHandle; // Handle for VPU library calls + VpuDecOutFrameInfo m_frameInfo; + }; + + class CDVDVideoCodecIMX : public CDVDVideoCodec + { ++ friend class CDVDVideoCodecIMXBuffer; ++ + public: + CDVDVideoCodecIMX(); + virtual ~CDVDVideoCodecIMX(); +@@ -94,7 +96,7 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + const char *m_pFormatName; // Current decoder format name + VpuDecOpenParam m_decOpenParam; // Parameters required to call VPU_DecOpen + DecMemInfo m_decMemInfo; // VPU dedicated memory description +- VpuDecHandle m_vpuHandle; // Handle for VPU library calls ++ static VpuDecHandle m_vpuHandle; // Handle for VPU library calls + VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start + void *m_tsm; // fsl Timestamp manager (from gstreamer implementation) + bool m_tsSyncRequired; // state whether timestamp manager has to be sync'ed +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h +index 18078d3..6096bf4 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h +@@ -21,15 +21,16 @@ + #ifndef DVDVIDEOCODECINFO_H + #define DVDVIDEOCODECINFO_H + +-#include "cores/VideoRenderers/RenderFormats.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 + }; +diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +index a823b69..7a03b4f 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ++++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp +@@ -996,6 +996,7 @@ static std::string GetRenderFormatName(ERenderFormat format) + 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 --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 4ac19c4..b44d4b8 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -52,7 +52,7 @@ bool CEGLNativeTypeIMX::CheckCompatibility() + void CEGLNativeTypeIMX::Initialize() + { + struct mxcfb_gbl_alpha alpha; +- int fd, fd2; ++ int fd; + + + fd = open("/dev/fb0",O_RDWR); +@@ -61,46 +61,20 @@ void CEGLNativeTypeIMX::Initialize() + CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); + return; + } +- fd2 = open("/dev/fb1",O_RDWR); +- if (fd2 < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while opening /dev/fb1.\n", __FUNCTION__); +- return; +- } +- + /* Store screen info */ + if (ioctl(fd, FBIOGET_VSCREENINFO, &m_screeninfo) != 0) + { + CLog::Log(LOGERROR, "%s - Error while querying frame buffer.\n", __FUNCTION__); + return; + } +- /* Configure overlay in the same way as BG plane */ +- if (ioctl(fd2, FBIOPUT_VSCREENINFO, &m_screeninfo) != 0) +- { +- CLog::Log(LOGERROR, "%s - Error while setting overlay frame buffer.\n", __FUNCTION__); +- return; +- } + +- /* set fb0 as the only visible layer - ioctl on /dev/fb0 so that fb0 is BG and fb1 is FG */ +- alpha.alpha = 255; +- alpha.enable = 1; +- if (ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha) != 0) +- { +- CLog::Log(LOGERROR, "%s - Error while initializing frame buffer.\n", __FUNCTION__); +- } +- + /* Unblank the fbs */ + if (ioctl(fd, FBIOBLANK, 0) < 0) + { + CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__); + } +- if (ioctl(fd2, FBIOBLANK, 0) < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__); +- } + + close(fd); +- close(fd2); + + return; + } +@@ -109,7 +83,6 @@ void CEGLNativeTypeIMX::Destroy() + { + struct fb_fix_screeninfo fixed_info; + void *fb_buffer; +- struct mxcfb_gbl_alpha alpha; + int fd; + + fd = open("/dev/fb0",O_RDWR); +@@ -118,13 +91,6 @@ void CEGLNativeTypeIMX::Destroy() + CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); + return; + } +- /* only fb0 visible */ +- alpha.alpha = 255; +- alpha.enable = 1; +- if (ioctl(fd, MXCFB_SET_GBL_ALPHA, &alpha) != 0) +- { +- CLog::Log(LOGERROR, "%s - Error while initializing frame buffer.\n", __FUNCTION__); +- } + + ioctl( fd, FBIOGET_FSCREENINFO, &fixed_info); + /* Black fb0 */ +@@ -140,19 +106,6 @@ void CEGLNativeTypeIMX::Destroy() + } + + close(fd); +- +- /* Blank overlay */ +- fd = open("/dev/fb1",O_RDWR); +- if (fd < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while opening /dev/fb1.\n", __FUNCTION__); +- return; +- } +- if (ioctl(fd, FBIOBLANK, 1) < 0) +- { +- CLog::Log(LOGERROR, "%s - Error while blanking fb1.\n", __FUNCTION__); +- } +- close(fd); + + return; + } +-- +1.9.3 + + +From 4cc2f136bb116a2be3307bbdeedab749d99447f1 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Mon, 17 Feb 2014 22:09:19 +0100 +Subject: [PATCH 05/56] Fixed include and display size issues + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 6 +++ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 61 ++++++++++++---------- + 2 files changed, 39 insertions(+), 28 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 0c8b357..4f3d042 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -26,6 +26,9 @@ + #endif + + #if HAS_GLES == 2 ++#ifdef HAS_IMXVPU ++#define GL_GLEXT_PROTOTYPES ++#endif + #include "system_gl.h" + + #include +@@ -2727,6 +2730,9 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + plane.texheight = codecinfo->iHeight; + + CalculateTextureSourceRects(index, 1); ++ ++ CLog::Log(LOGDEBUG, "U %dx%d -> %dx%d", codecinfo->iWidth, codecinfo->iHeight, ++ plane.rect.x2-plane.rect.x1, plane.rect.y2-plane.rect.y1); + #endif + } + void CLinuxRendererGLES::DeleteIMXMAPTexture(int index) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 7c5c26b..a5d9eeb 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -510,6 +510,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; + bool retry = false; ++ bool frameConsumed = false; + + #ifdef IMX_PROFILE + static unsigned long long previous, current; +@@ -548,31 +549,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + CLog::Log(LOGERROR,"%s - bitstream_convert error", __FUNCTION__); + } + +- if (pts != DVD_NOPTS_VALUE) +- { +- if (m_tsSyncRequired) +- { +- m_tsSyncRequired = false; +- resyncTSManager(m_tsm, llrint(pts) * 1000, MODE_AI); +- } +- //TSManagerReceive2(m_tsm, llrint(pts) * 1000, iSize); +- TSManagerReceive(m_tsm, llrint(pts) * 1000); +- } +- else +- { +- //If no pts but dts available (AVI container for instance) then use this one +- if (dts != DVD_NOPTS_VALUE) +- { +- if (m_tsSyncRequired) +- { +- m_tsSyncRequired = false; +- resyncTSManager(m_tsm, llrint(dts) * 1000, MODE_AI); +- } +- //TSManagerReceive2(m_tsm, llrint(dts) * 1000, iSize); +- TSManagerReceive(m_tsm, llrint(dts) * 1000); +- } +- } +- + inData.nSize = demuxer_bytes; + inData.pPhyAddr = NULL; + inData.pVirAddr = demuxer_content; +@@ -646,6 +622,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + CLog::Log(LOGERROR, "%s - VPU error retireving info about consummed frame (%d).\n", __FUNCTION__, ret); + } ++ frameConsumed = true; + // FIXME TSManagerValid2(m_tsm, frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength, frameLengthInfo.pFrame); + //CLog::Log(LOGDEBUG, "%s - size : %d - key consummed : %x\n", __FUNCTION__, frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength, frameLengthInfo.pFrame); + }//VPU_DEC_ONE_FRM_CONSUMED +@@ -710,7 +687,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + TSManagerSend(m_tsm); + } + +- + if (!(decRet & VPU_DEC_OUTPUT_DIS) && + (inData.nSize != 0)) + { +@@ -725,6 +701,34 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } while (retry == true); + } //(pData && iSize) + ++ if (frameConsumed) ++ { ++ if (pts != DVD_NOPTS_VALUE) ++ { ++ if (m_tsSyncRequired) ++ { ++ m_tsSyncRequired = false; ++ resyncTSManager(m_tsm, llrint(pts) * 1000, MODE_AI); ++ } ++ //TSManagerReceive2(m_tsm, llrint(pts) * 1000, iSize); ++ TSManagerReceive(m_tsm, llrint(pts) * 1000); ++ } ++ else ++ { ++ //If no pts but dts available (AVI container for instance) then use this one ++ if (dts != DVD_NOPTS_VALUE) ++ { ++ if (m_tsSyncRequired) ++ { ++ m_tsSyncRequired = false; ++ resyncTSManager(m_tsm, llrint(dts) * 1000, MODE_AI); ++ } ++ //TSManagerReceive2(m_tsm, llrint(dts) * 1000, iSize); ++ TSManagerReceive(m_tsm, llrint(dts) * 1000); ++ } ++ } ++ } ++ + if (retStatus == 0) + { + retStatus |= VC_BUFFER; +@@ -789,8 +793,9 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + 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 = m_frameInfo.pExtInfo->FrmCropRect.nRight - m_frameInfo.pExtInfo->FrmCropRect.nLeft; +- pDvdVideoPicture->iDisplayHeight = m_frameInfo.pExtInfo->FrmCropRect.nBottom - m_frameInfo.pExtInfo->FrmCropRect.nTop; ++ ++ pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; ++ pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + + pDvdVideoPicture->codecinfo = new CDVDVideoCodecIMXBuffer(m_frameInfo); + pDvdVideoPicture->codecinfo->iWidth = m_frameInfo.pExtInfo->nFrmWidth; +-- +1.9.3 + + +From 1e0617aeed91f814b48375f197cb7e5e16b76dc8 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Mon, 17 Feb 2014 23:26:07 +0100 +Subject: [PATCH 06/56] Removed debug output used for testing + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 4f3d042..2c7f132 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -2730,9 +2730,6 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + plane.texheight = codecinfo->iHeight; + + CalculateTextureSourceRects(index, 1); +- +- CLog::Log(LOGDEBUG, "U %dx%d -> %dx%d", codecinfo->iWidth, codecinfo->iHeight, +- plane.rect.x2-plane.rect.x1, plane.rect.y2-plane.rect.y1); + #endif + } + void CLinuxRendererGLES::DeleteIMXMAPTexture(int index) +-- +1.9.3 + + +From a425d31b4a87b5159a07944fb8921a081af4f09e Mon Sep 17 00:00:00 2001 +From: smallint +Date: Tue, 18 Feb 2014 16:07:23 +0000 +Subject: [PATCH 07/56] Attempt to fix potential race condition and + mutlithreading issues ... to be tested + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 130 ++++++++++++++++++--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 29 +++-- + 2 files changed, 135 insertions(+), 24 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index a5d9eeb..690ab65 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -43,7 +43,7 @@ + #define IMX_MAX_QUEUE_SIZE 1 + // 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 = IMX_MAX_QUEUE_SIZE + 6; +-VpuDecHandle CDVDVideoCodecIMX::m_vpuHandle = 0; ++CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock; + + bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + { +@@ -95,6 +95,17 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + return false; + } + ++int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr) ++{ ++ int i; ++ for (i=0; iInvalidate(); ++ SAFE_RELEASE(m_outputBuffers[i]); ++ } ++ ++ // Clear memory ++ if (m_outputBuffers != NULL) ++ { ++ delete m_outputBuffers; ++ m_outputBuffers = NULL; ++ } ++ + VpuFreeBuffers(); + m_vpuFrameBufferNum = 0; + +@@ -504,8 +539,8 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + VpuDecFrameLengthInfo frameLengthInfo; + VpuBufferNode inData; +- VpuDecRetCode ret; +- int decRet = 0; ++ VpuDecRetCode ret; ++ int decRet = 0, i; + int retStatus = 0; + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; +@@ -524,6 +559,21 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + return VC_ERROR; + } + ++ for (i=0; i < m_vpuFrameBufferNum; i++) ++ { ++ if (m_outputBuffers[i]->Rendered()) ++ { ++ ret = VPU_DecOutFrameDisplayed(m_vpuHandle, &m_vpuFrameBuffers[i]); ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "- %02d\n", i); ++#endif ++ 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); +@@ -797,11 +847,27 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->iDisplayWidth = ((pDvdVideoPicture->iWidth * m_frameInfo.pExtInfo->nQ16ShiftWidthDivHeightRatio) + 32767) >> 16; + pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + +- pDvdVideoPicture->codecinfo = new CDVDVideoCodecIMXBuffer(m_frameInfo); +- pDvdVideoPicture->codecinfo->iWidth = m_frameInfo.pExtInfo->nFrmWidth; +- pDvdVideoPicture->codecinfo->iHeight = m_frameInfo.pExtInfo->nFrmHeight; +- pDvdVideoPicture->codecinfo->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; +- pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufY; ++ int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); ++ if (idx == -1) ++ { ++ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); ++ } ++ else ++ { ++ CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; ++ buffer->Queue(&m_vpuFrameBuffers[idx]); ++ pDvdVideoPicture->codecinfo = buffer; ++ ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "+ %02d\n", idx); ++#endif ++ ++ pDvdVideoPicture->codecinfo->Lock(); ++ pDvdVideoPicture->codecinfo->iWidth = m_frameInfo.pExtInfo->nFrmWidth; ++ pDvdVideoPicture->codecinfo->iHeight = m_frameInfo.pExtInfo->nFrmHeight; ++ pDvdVideoPicture->codecinfo->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; ++ pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufY; ++ } + + return true; + } +@@ -822,9 +888,16 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) + + /*******************************************/ + +-CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(VpuDecOutFrameInfo frameInfo) ++#ifdef TRACE_FRAMES ++CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer(int idx) + : m_refs(1) +- , m_frameInfo(frameInfo) ++ , m_idx(idx) ++#else ++CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() ++ : m_refs(1) ++#endif ++ , m_frameBuffer(NULL) ++ , m_rendered(false) + { + } + +@@ -836,13 +909,18 @@ void CDVDVideoCodecIMXBuffer::Lock() + long CDVDVideoCodecIMXBuffer::Release() + { + long count = AtomicDecrement(&m_refs); +- if (count == 0) ++ if (count == 1) + { +- VpuDecRetCode ret = VPU_DecOutFrameDisplayed(CDVDVideoCodecIMX::m_vpuHandle, m_frameInfo.pDisplayFrameBuf); +- if(ret != VPU_DEC_RET_SUCCESS) +- { +- CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); +- } ++ // 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. ++ m_rendered = true; ++ } ++ else if (count == 0) ++ { ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "~ %02d\n", m_idx); ++#endif ++ + delete this; + } + +@@ -851,7 +929,25 @@ long CDVDVideoCodecIMXBuffer::Release() + + bool CDVDVideoCodecIMXBuffer::IsValid() + { +- return (CDVDVideoCodecIMX::m_vpuHandle != 0); ++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++ return m_frameBuffer != NULL; ++} ++ ++void CDVDVideoCodecIMXBuffer::Invalidate() ++{ ++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++ m_frameBuffer = NULL; ++} ++ ++bool CDVDVideoCodecIMXBuffer::Rendered() ++{ ++ return m_rendered; ++} ++ ++void CDVDVideoCodecIMXBuffer::Queue(VpuFrameBuffer *buffer) ++{ ++ m_frameBuffer = buffer; ++ m_rendered = false; + } + + CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 5487bfe..df568e5 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -29,6 +29,7 @@ + + + //#define IMX_PROFILE ++#define TRACE_FRAMES + + /* FIXME TODO Develop real proper CVPUBuffer class */ + #define VPU_DEC_MAX_NUM_MEM_NUM 20 +@@ -49,19 +50,31 @@ typedef struct + class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + { + public: +- CDVDVideoCodecIMXBuffer(VpuDecOutFrameInfo frameInfo); ++#ifdef TRACE_FRAMES ++ CDVDVideoCodecIMXBuffer(int idx); ++#else ++ CDVDVideoCodecIMXBuffer(); ++#endif + + // reference counting +- virtual void Lock(); +- virtual long Release(); +- virtual bool IsValid(); ++ virtual void Lock(); ++ virtual long Release(); ++ virtual bool IsValid(); ++ ++ void Invalidate(); ++ bool Rendered(); ++ void Queue(VpuFrameBuffer *buffer); + + protected: + // private because we are reference counted + virtual ~CDVDVideoCodecIMXBuffer(); + ++#ifdef TRACE_FRAMES ++ int m_idx; ++#endif + long m_refs; +- VpuDecOutFrameInfo m_frameInfo; ++ VpuFrameBuffer *m_frameBuffer; ++ bool m_rendered; + }; + + class CDVDVideoCodecIMX : public CDVDVideoCodec +@@ -89,20 +102,23 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + bool VpuAllocBuffers(VpuMemInfo *); + bool VpuFreeBuffers(void); + bool VpuAllocFrameBuffers(void); ++ int VpuFindBuffer(void *frameAddr); + + static const int m_extraVpuBuffers; // Number of additional buffers for VPU ++ 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 + DecMemInfo m_decMemInfo; // VPU dedicated memory description +- static VpuDecHandle m_vpuHandle; // Handle for VPU library calls ++ VpuDecHandle m_vpuHandle; // Handle for VPU library calls + VpuDecInitInfo m_initInfo; // Initial info returned from VPU at decoding start + void *m_tsm; // fsl Timestamp manager (from gstreamer implementation) + bool m_tsSyncRequired; // state whether timestamp manager has to be sync'ed + bool m_dropState; // Current drop state + int m_vpuFrameBufferNum; // Total number of allocated frame buffers + VpuFrameBuffer *m_vpuFrameBuffers; // Table of VPU frame buffers description ++ CDVDVideoCodecIMXBuffer **m_outputBuffers; + VpuMemDesc *m_extraMem; // Table of allocated extra Memory + // VpuMemDesc *m_outputBuffers; // Table of buffers out of VPU (used to call properly VPU_DecOutFrameDisplayed) + int m_frameCounter; // Decoded frames counter +@@ -110,5 +126,4 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + VpuDecOutFrameInfo m_frameInfo; + CBitstreamConverter *m_converter; + bool m_convert_bitstream; +- + }; +-- +1.9.3 + + +From 0a82a632aac1bb0abb9079a6a690d832ca918017 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Tue, 18 Feb 2014 19:19:09 +0100 +Subject: [PATCH 08/56] Fixed buffer reference and added more logs to track a + frames lifetime + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 28 ++++++++++++++++++---- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 1 + + 3 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 2c7f132..5e03110 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -2740,6 +2740,8 @@ void CLinuxRendererGLES::DeleteIMXMAPTexture(int index) + if(plane.id && glIsTexture(plane.id)) + glDeleteTextures(1, &plane.id); + plane.id = 0; ++ ++ SAFE_RELEASE(buf.codecinfo); + } + bool CLinuxRendererGLES::CreateIMXMAPTexture(int index) + { +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 690ab65..75aba7c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -563,10 +563,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + if (m_outputBuffers[i]->Rendered()) + { +- ret = VPU_DecOutFrameDisplayed(m_vpuHandle, &m_vpuFrameBuffers[i]); +-#ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "- %02d\n", i); +-#endif ++ ret = m_outputBuffers[i]->ClearDisplay(&m_vpuHandle); + if(ret != VPU_DEC_RET_SUCCESS) + { + CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); +@@ -855,7 +852,7 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + else + { + CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; +- buffer->Queue(&m_vpuFrameBuffers[idx]); ++ buffer->Queue(m_frameInfo.pDisplayFrameBuf); + pDvdVideoPicture->codecinfo = buffer; + + #ifdef TRACE_FRAMES +@@ -903,17 +900,28 @@ CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() + + void CDVDVideoCodecIMXBuffer::Lock() + { ++#ifdef TRACE_FRAMES ++ long count = AtomicIncrement(&m_refs); ++ CLog::Log(LOGDEBUG, "R+ %02d - ref : %d\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\n", m_idx, count); ++#endif + 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. + m_rendered = true; ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "R %02d\n", m_idx); ++#endif + } + else if (count == 0) + { +@@ -950,6 +958,16 @@ void CDVDVideoCodecIMXBuffer::Queue(VpuFrameBuffer *buffer) + m_rendered = false; + } + ++VpuDecRetCode CDVDVideoCodecIMXBuffer::ClearDisplay(VpuDecHandle *handle) ++{ ++ VpuDecRetCode ret = VPU_DecOutFrameDisplayed(*handle, m_frameBuffer); ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "- %02d\n", m_idx); ++#endif ++ m_rendered = false; ++ return ret; ++} ++ + CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() + { + assert(m_refs == 0); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index df568e5..1aef626 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -64,6 +64,7 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + void Invalidate(); + bool Rendered(); + void Queue(VpuFrameBuffer *buffer); ++ VpuDecRetCode ClearDisplay(VpuDecHandle *handle); + + protected: + // private because we are reference counted +-- +1.9.3 + + +From b7057e10de5fce70abb5eebbb00c92bf39a35545 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Tue, 18 Feb 2014 20:03:46 +0100 +Subject: [PATCH 09/56] Missing initialization and extradata handling backport + from wolfgar + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 75aba7c..f3a7adc 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -320,6 +320,7 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + memset(&m_decMemInfo, 0, sizeof(DecMemInfo)); + m_vpuHandle = 0; + m_vpuFrameBuffers = NULL; ++ m_outputBuffers = NULL; + m_extraMem = NULL; + m_vpuFrameBufferNum = 0; + m_tsSyncRequired = true; +@@ -393,14 +394,14 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + case CODEC_ID_H264: + m_decOpenParam.CodecFormat = VPU_V_AVC; + m_pFormatName = "iMX-h264"; +- if (hints.extrasize < 7 || hints.extradata == NULL) ++ if (hints.extradata) + { +- CLog::Log(LOGNOTICE, +- "%s - avcC data too small or missing", __FUNCTION__); +- return false; ++ if ( *(char*)hints.extradata == 1 ) ++ { ++ m_converter = new CBitstreamConverter(); ++ m_convert_bitstream = m_converter->Open(hints.codec, (uint8_t *)hints.extradata, hints.extrasize, true); ++ } + } +- 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; +-- +1.9.3 + + +From 39919bed88a47c97b1a404d4df490ed49d8f6715 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Tue, 18 Feb 2014 22:38:31 +0100 +Subject: [PATCH 10/56] Added safety check to render texture and moved + invalidation of frames before destroying the VPU handle + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 3 +++ + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 14 +++++++------- + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 5e03110..cef2f65 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -1632,6 +1632,9 @@ void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) + #endif + + YUVPLANE &plane = m_buffers[index].fields[field][0]; ++ CDVDVideoCodecBuffer* codecinfo = m_buffers[index].codecinfo; ++ ++ if((codecinfo == NULL) || !codecinfo->IsValid()) return; + + glDisable(GL_DEPTH_TEST); + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index f3a7adc..6689261 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -475,6 +475,13 @@ void CDVDVideoCodecIMX::Dispose(void) + bool VPU_loaded = m_vpuHandle; + int i; + ++ // Invalidate output buffers to prevent the renderer from mapping this memory ++ for (i=0; iInvalidate(); ++ SAFE_RELEASE(m_outputBuffers[i]); ++ } ++ + if (m_vpuHandle) + { + ret = VPU_DecFlushAll(m_vpuHandle); +@@ -490,13 +497,6 @@ void CDVDVideoCodecIMX::Dispose(void) + m_vpuHandle = 0; + } + +- // Invalidate output buffers to prevent the renderer from mapping this memory +- for (i=0; iInvalidate(); +- SAFE_RELEASE(m_outputBuffers[i]); +- } +- + // Clear memory + if (m_outputBuffers != NULL) + { +-- +1.9.3 + + +From 55036f10d747b957a18f6fb3439a918747a5713b Mon Sep 17 00:00:00 2001 +From: smallint +Date: Tue, 18 Feb 2014 23:29:48 +0100 +Subject: [PATCH 11/56] Added Reset of buffers + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 6689261..a6de84f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -793,13 +793,17 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + + void CDVDVideoCodecIMX::Reset() + { +- int ret; ++ int ret, i; + + CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); + + /* We have to resync timestamp manager */ + m_tsSyncRequired = true; + ++ /* Invalidate all buffers */ ++ for(int i = 0; i < m_vpuFrameBufferNum; i++) ++ m_outputBuffers[i]->Invalidate(); ++ + /* Flush VPU */ + ret = VPU_DecFlushAll(m_vpuHandle); + if (ret != VPU_DEC_RET_SUCCESS) +@@ -946,6 +950,7 @@ void CDVDVideoCodecIMXBuffer::Invalidate() + { + CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); + m_frameBuffer = NULL; ++ m_rendered = false; + } + + bool CDVDVideoCodecIMXBuffer::Rendered() +-- +1.9.3 + + +From 9244890a694fac56c7005dd90e42841ea1c797eb Mon Sep 17 00:00:00 2001 +From: smallint +Date: Wed, 19 Feb 2014 00:29:48 +0100 +Subject: [PATCH 12/56] Fixed lost frames when seeking + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 22 +++++++++++++++++----- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 2 +- + 2 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index a6de84f..7e26756 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -478,7 +478,7 @@ void CDVDVideoCodecIMX::Dispose(void) + // Invalidate output buffers to prevent the renderer from mapping this memory + for (i=0; iInvalidate(); ++ m_outputBuffers[i]->Invalidate(&m_vpuHandle); + SAFE_RELEASE(m_outputBuffers[i]); + } + +@@ -801,8 +801,8 @@ void CDVDVideoCodecIMX::Reset() + m_tsSyncRequired = true; + + /* Invalidate all buffers */ +- for(int i = 0; i < m_vpuFrameBufferNum; i++) +- m_outputBuffers[i]->Invalidate(); ++ for(i = 0; i < m_vpuFrameBufferNum; i++) ++ m_outputBuffers[i]->Invalidate(&m_vpuHandle); + + /* Flush VPU */ + ret = VPU_DecFlushAll(m_vpuHandle); +@@ -923,7 +923,8 @@ long CDVDVideoCodecIMXBuffer::Release() + { + // 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. +- m_rendered = true; ++ if(m_frameBuffer != NULL) ++ m_rendered = true; + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "R %02d\n", m_idx); + #endif +@@ -946,9 +947,19 @@ bool CDVDVideoCodecIMXBuffer::IsValid() + return m_frameBuffer != NULL; + } + +-void CDVDVideoCodecIMXBuffer::Invalidate() ++void CDVDVideoCodecIMXBuffer::Invalidate(VpuDecHandle *handle) + { + CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "I %02d\n", m_idx); ++#endif ++ if((m_frameBuffer != NULL) && *handle) ++ { ++ VpuDecRetCode 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); ++ } ++ + m_frameBuffer = NULL; + m_rendered = false; + } +@@ -971,6 +982,7 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ClearDisplay(VpuDecHandle *handle) + CLog::Log(LOGDEBUG, "- %02d\n", m_idx); + #endif + m_rendered = false; ++ m_frameBuffer = NULL; + return ret; + } + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 1aef626..b17e51b 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -61,7 +61,7 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + virtual long Release(); + virtual bool IsValid(); + +- void Invalidate(); ++ void Invalidate(VpuDecHandle *handle); + bool Rendered(); + void Queue(VpuFrameBuffer *buffer); + VpuDecRetCode ClearDisplay(VpuDecHandle *handle); +-- +1.9.3 + + +From f23871c5d85ee1c9965b119fceda6b35c7a790e8 Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Wed, 19 Feb 2014 02:18:24 +0100 +Subject: [PATCH 13/56] Change copyright notice to remove explicit mention of + my name and be compliant with xbmc rules for upstreaming + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 7e26756..58075bc 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -1,5 +1,6 @@ +-/* +- * Copyright (C) 2013 Stephan Rafin ++/* ++ * 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 +-- +1.9.3 + + +From 19c41ffeb9242e19abd1cab0be18adac2f10735b Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Wed, 19 Feb 2014 03:19:00 +0100 +Subject: [PATCH 14/56] Fix includes for yocto cross toolchain + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index cef2f65..f731beb 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -84,8 +84,8 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + + #ifdef HAS_IMXVPU + // GLES extension functions +-#include +-#include ++#include ++#include + #endif + + #if defined(TARGET_ANDROID) +-- +1.9.3 + + +From a4067d060f5a367c3a15a2f5c171f5cca6b9bb95 Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Wed, 19 Feb 2014 03:25:10 +0100 +Subject: [PATCH 15/56] pts simplification (merge latest changes from my imxpts + branch) + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 102 +++++++++------------ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 6 +- + 2 files changed, 48 insertions(+), 60 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 58075bc..13be3fc 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -30,7 +30,6 @@ + #include "threads/SingleLock.h" + #include "utils/log.h" + #include "DVDClock.h" +-#include "mfw_gst_ts.h" + #include "threads/Atomics.h" + + +@@ -199,10 +198,6 @@ bool CDVDVideoCodecIMX::VpuOpen(void) + goto VpuOpenError; + } + +- /* Initialize ts manager */ +- m_tsm = createTSManager(0); +- setTSManagerFrameRate(m_tsm, m_hints.fpsrate, m_hints.fpsscale); +- + return true; + + VpuOpenError: +@@ -326,7 +321,6 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + m_vpuFrameBufferNum = 0; + m_tsSyncRequired = true; + m_dropState = false; +- m_tsm = NULL; + m_convert_bitstream = false; + m_frameCounter = 0; + m_usePTS = true; +@@ -523,12 +517,6 @@ void CDVDVideoCodecIMX::Dispose(void) + } + } + +- if (m_tsm != NULL) +- { +- destroyTSManager(m_tsm); +- m_tsm = NULL; +- } +- + if (m_converter) + { + m_converter->Close(); +@@ -547,7 +535,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; + bool retry = false; +- bool frameConsumed = false; ++ int idx; + + #ifdef IMX_PROFILE + static unsigned long long previous, current; +@@ -671,9 +659,25 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + CLog::Log(LOGERROR, "%s - VPU error retireving info about consummed frame (%d).\n", __FUNCTION__, ret); + } +- frameConsumed = true; +- // FIXME TSManagerValid2(m_tsm, frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength, frameLengthInfo.pFrame); +- //CLog::Log(LOGDEBUG, "%s - size : %d - key consummed : %x\n", __FUNCTION__, frameLengthInfo.nFrameLength + frameLengthInfo.nStuffLength, frameLengthInfo.pFrame); ++ if (frameLengthInfo.pFrame) ++ { ++ idx = VpuFindBuffer(frameLengthInfo.pFrame->pbufY); ++ if (idx != -1) ++ { ++ if (pts != DVD_NOPTS_VALUE) ++ { ++ m_outputBuffers[idx]->SetPts(pts); ++ } ++ else if (dts != DVD_NOPTS_VALUE) ++ { ++ m_outputBuffers[idx]->SetPts(dts); ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); ++ } ++ } + }//VPU_DEC_ONE_FRM_CONSUMED + + if ((decRet & VPU_DEC_OUTPUT_DIS) || +@@ -694,12 +698,10 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + + if (decRet & VPU_DEC_OUTPUT_REPEAT) + { +- TSManagerSend(m_tsm); + CLog::Log(LOGDEBUG, "%s - Frame repeat.\n", __FUNCTION__); + } + if (decRet & VPU_DEC_OUTPUT_DROPPED) + { +- TSManagerSend(m_tsm); + CLog::Log(LOGDEBUG, "%s - Frame dropped.\n", __FUNCTION__); + } + if (decRet & VPU_DEC_NO_ENOUGH_BUF) +@@ -708,7 +710,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } + if (decRet & VPU_DEC_SKIP) + { +- TSManagerSend(m_tsm); + CLog::Log(LOGDEBUG, "%s - Frame skipped.\n", __FUNCTION__); + } + if (decRet & VPU_DEC_FLUSH) +@@ -733,7 +734,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + if (!(decRet & VPU_DEC_INPUT_USED)) + { + CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize); +- TSManagerSend(m_tsm); + } + + if (!(decRet & VPU_DEC_OUTPUT_DIS) && +@@ -750,34 +750,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } while (retry == true); + } //(pData && iSize) + +- if (frameConsumed) +- { +- if (pts != DVD_NOPTS_VALUE) +- { +- if (m_tsSyncRequired) +- { +- m_tsSyncRequired = false; +- resyncTSManager(m_tsm, llrint(pts) * 1000, MODE_AI); +- } +- //TSManagerReceive2(m_tsm, llrint(pts) * 1000, iSize); +- TSManagerReceive(m_tsm, llrint(pts) * 1000); +- } +- else +- { +- //If no pts but dts available (AVI container for instance) then use this one +- if (dts != DVD_NOPTS_VALUE) +- { +- if (m_tsSyncRequired) +- { +- m_tsSyncRequired = false; +- resyncTSManager(m_tsm, llrint(dts) * 1000, MODE_AI); +- } +- //TSManagerReceive2(m_tsm, llrint(dts) * 1000, iSize); +- TSManagerReceive(m_tsm, llrint(dts) * 1000); +- } +- } +- } +- + if (retStatus == 0) + { + retStatus |= VC_BUFFER; +@@ -838,11 +810,6 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->iFlags &= ~DVP_FLAG_DROPPED; + + pDvdVideoPicture->format = RENDER_FMT_IMXMAP; +- pDvdVideoPicture->pts = (double)TSManagerSend(m_tsm) / (double)1000.0; +- if (!m_usePTS) +- { +- pDvdVideoPicture->pts = DVD_NOPTS_VALUE; +- } + 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; +@@ -851,18 +818,20 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight; + + int idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); +- if (idx == -1) +- { +- CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); +- } +- else ++ if (idx != -1) + { + CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; ++ pDvdVideoPicture->pts = buffer->GetPts(); ++ if (!m_usePTS) ++ { ++ pDvdVideoPicture->pts = DVD_NOPTS_VALUE; ++ } + buffer->Queue(m_frameInfo.pDisplayFrameBuf); + pDvdVideoPicture->codecinfo = buffer; + + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "+ %02d\n", idx); ++ CLog::Log(LOGDEBUG, "pts %f\n",pDvdVideoPicture->pts); + #endif + + pDvdVideoPicture->codecinfo->Lock(); +@@ -871,6 +840,10 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->codecinfo->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; + pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufY; + } ++ else ++ { ++ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); ++ } + + return true; + } +@@ -901,6 +874,7 @@ CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() + #endif + , m_frameBuffer(NULL) + , m_rendered(false) ++ , m_pts(DVD_NOPTS_VALUE) + { + } + +@@ -963,6 +937,7 @@ void CDVDVideoCodecIMXBuffer::Invalidate(VpuDecHandle *handle) + + m_frameBuffer = NULL; + m_rendered = false; ++ m_pts = DVD_NOPTS_VALUE; + } + + bool CDVDVideoCodecIMXBuffer::Rendered() +@@ -984,9 +959,20 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ClearDisplay(VpuDecHandle *handle) + #endif + m_rendered = false; + m_frameBuffer = NULL; ++ m_pts = DVD_NOPTS_VALUE; + return ret; + } + ++void CDVDVideoCodecIMXBuffer::SetPts(double pts) ++{ ++ m_pts = pts; ++} ++ ++double CDVDVideoCodecIMXBuffer::GetPts(void) const ++{ ++ return m_pts; ++} ++ + CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() + { + assert(m_refs == 0); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index b17e51b..c4418fe 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -29,7 +29,7 @@ + + + //#define IMX_PROFILE +-#define TRACE_FRAMES ++//#define TRACE_FRAMES + + /* FIXME TODO Develop real proper CVPUBuffer class */ + #define VPU_DEC_MAX_NUM_MEM_NUM 20 +@@ -65,6 +65,8 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + bool Rendered(); + void Queue(VpuFrameBuffer *buffer); + VpuDecRetCode ClearDisplay(VpuDecHandle *handle); ++ void SetPts(double pts); ++ double GetPts(void) const; + + protected: + // private because we are reference counted +@@ -76,6 +78,7 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + long m_refs; + VpuFrameBuffer *m_frameBuffer; + bool m_rendered; ++ double m_pts; + }; + + class CDVDVideoCodecIMX : public CDVDVideoCodec +@@ -114,7 +117,6 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + DecMemInfo 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 +- void *m_tsm; // fsl Timestamp manager (from gstreamer implementation) + bool m_tsSyncRequired; // state whether timestamp manager has to be sync'ed + bool m_dropState; // Current drop state + int m_vpuFrameBufferNum; // Total number of allocated frame buffers +-- +1.9.3 + + +From 3aec4fcadb8200b6b75f9a5738e902a1d28183da Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Wed, 19 Feb 2014 04:08:19 +0100 +Subject: [PATCH 16/56] Remove mfw_gst_ts from build + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in | 2 +- + xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c | 752 ---------------------- + xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h | 170 ----- + 3 files changed, 1 insertion(+), 923 deletions(-) + delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c + delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +index 1df37c6..d019a91 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in +@@ -25,7 +25,7 @@ SRCS += OpenMaxVideo.cpp + SRCS += DVDVideoCodecOpenMax.cpp + endif + ifeq (@USE_IMXVPU@,1) +-SRCS += DVDVideoCodecIMX.cpp mfw_gst_ts.c ++SRCS += DVDVideoCodecIMX.cpp + endif + ifeq (@USE_LIBAMCODEC@,1) + SRCS += AMLCodec.cpp +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c b/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c +deleted file mode 100644 +index 86a8fea..0000000 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.c ++++ /dev/null +@@ -1,752 +0,0 @@ +-/* +- * Copyright (c) 2010-2012, Freescale Semiconductor, Inc. All rights reserved. +- * +- */ +- +-/* +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Library General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This library 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 +- * Library General Public License for more details. +- * +- * You should have received a copy of the GNU Library General Public +- * License along with this library; if not, write to the +- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, +- * Boston, MA 02111-1307, USA. +- */ +- +-/* +- * Module Name: TimeStamp.c +- * +- * Description: include TimeStamp stratege for VPU / SW video decoder plugin +- * +- * Portability: This code is written for Linux OS and Gstreamer +- */ +- +-/* +- * Changelog: +- 11/2/2010 draft version Lyon Wang +- * +- */ +-#include +-#include +-#include +- +-#include "mfw_gst_ts.h" +- +- +-const char *debug_env = "ME_DEBUG"; +-char *debug = NULL; +-int debug_level = 0; +- +- +-enum +-{ +- DEBUG_LEVEL_ERROR = 1, +- DEBUG_LEVEL_WARNING, +- DEBUG_LEVEL_LOG, +- DEBUG_LEVEL_VERBOSE, +-}; +- +- +-#define TSM_MESSAGE(level, fmt, ...)\ +- do{\ +- if (debug_level>=(level)){\ +- printf("TSM:"fmt, ##__VA_ARGS__);\ +- }\ +- }while(0) +- +-#define TSM_ERROR(...) TSM_MESSAGE(DEBUG_LEVEL_ERROR, ##__VA_ARGS__) +-#define TSM_WARNING(...) TSM_MESSAGE(DEBUG_LEVEL_WARNING, ##__VA_ARGS__) +-#define TSM_LOG(...) TSM_MESSAGE(DEBUG_LEVEL_LOG, ##__VA_ARGS__) +-#define TSM_VERBOSE(...) TSM_MESSAGE(DEBUG_LEVEL_VERBOSE, ##__VA_ARGS__) +- +-#define TSM_HISTORY_POWER 5 +-#define TSM_HISTORY_SIZE (1<dur_history_total>>TSM_HISTORY_POWER) +- +-#define TSM_SECOND ((TSM_TIMESTAMP)1000000000) +-#define TSM_DEFAULT_INTERVAL (TSM_SECOND/30) +-#define TSM_DEFAULT_TS_BUFFER_SIZE (128) +- +-#define TSM_TS_IS_VALID(ts) \ +- ((ts) != TSM_TIMESTAMP_NONE) +- +-#define TSM_KEY_IS_VALID(key) \ +- ((key) != TSM_KEY_NONE) +- +-#define TSM_DISTANCE(tsm)\ +- (((tsm->rx)>=(tsm->tx))?((tsm->rx)-(tsm->tx)):(tsm->ts_buf_size-(tsm->tx)+(tsm->rx))) +- +-#define TSM_PLUS_AGE(tsm)\ +- (TSM_DISTANCE(tsm)+tsm->invalid_ts_count+2) +- +-#define TSM_ABS(ts0, ts1)\ +- (((ts0)>(ts1))?((ts0)-(ts1)):((ts1)-(ts0))) +- +-#define TSM_TIME_FORMAT "u:%02u:%02u.%09u" +- +-#define TSM_TIME_ARGS(t) \ +- TSM_TS_IS_VALID (t) ? \ +- (unsigned int) (((TSM_TIMESTAMP)(t)) / (TSM_SECOND * 60 * 60)) : 99, \ +- TSM_TS_IS_VALID (t) ? \ +- (unsigned int) ((((TSM_TIMESTAMP)(t)) / (TSM_SECOND * 60)) % 60) : 99, \ +- TSM_TS_IS_VALID (t) ? \ +- (unsigned int) ((((TSM_TIMESTAMP)(t)) / TSM_SECOND) % 60) : 99, \ +- TSM_TS_IS_VALID (t) ? \ +- (unsigned int) (((TSM_TIMESTAMP)(t)) % TSM_SECOND) : 999999999 +- +-#define TSM_BUFFER_SET(buf, value, size) \ +- do {\ +- int i;\ +- for (i=0;i<(size);i++){\ +- (buf)[i] = (value);\ +- }\ +- }while(0) +- +-#define TSM_RECEIVED_NUNBER 512 +- +- +-typedef struct +-{ +- TSM_TIMESTAMP ts; +- unsigned long long age; +- void *key; +-} TSMControl; +- +-typedef struct _TSMReceivedEntry +-{ +- TSM_TIMESTAMP ts; +- struct _TSMReceivedEntry *next; +- unsigned int used:1; +- unsigned int subentry:1; +- int size; +-} TSMReceivedEntry; +- +-typedef struct _TSMReceivedEntryMemory +-{ +- struct _TSMReceivedEntryMemory *next; +- TSMReceivedEntry entrys[TSM_RECEIVED_NUNBER]; +-} TSMReceivedEntryMemory; +- +-typedef struct +-{ +- TSMReceivedEntry *head; +- TSMReceivedEntry *tail; +- TSMReceivedEntry *free; +- TSMReceivedEntryMemory *memory; +- int cnt; +-} TSMRecivedCtl; +- +-typedef struct _TSManager +-{ +- int first_tx; +- int first_rx; +- int rx; //timestamps received +- int tx; //timestamps transfered +- TSM_TIMESTAMP last_ts_sent; //last time stamp sent +- TSM_TIMESTAMP last_ts_received; +- TSM_TIMESTAMP suspicious_ts; +- +- TSM_TIMESTAMP discont_threshold; +- +- unsigned int invalid_ts_count; +- TSMGR_MODE mode; +- int ts_buf_size; +- int dur_history_tx; +- TSM_TIMESTAMP dur_history_total; +- TSM_TIMESTAMP dur_history_buf[TSM_HISTORY_SIZE]; +- TSMControl *ts_buf; +- unsigned long long age; +- int tx_cnt; +- int rx_cnt; +- int cnt; +- int valid_ts_received:1; +- int big_cnt; +- +- TSMRecivedCtl rctl; +-} TSManager; +- +- +-static void +-tsm_free_received_entry (TSMRecivedCtl * rctl, TSMReceivedEntry * entry) +-{ +- entry->next = rctl->free; +- rctl->free = entry; +-} +- +- +-static TSMReceivedEntry * +-tsm_new_received_entry (TSMRecivedCtl * rctl) +-{ +- TSMReceivedEntry *ret = NULL; +- if (rctl->free) { +- ret = rctl->free; +- rctl->free = ret->next; +- } else { +- TSMReceivedEntryMemory *p = malloc (sizeof (TSMReceivedEntryMemory)); +- if (p) { +- int i; +- for (i = 1; i < TSM_RECEIVED_NUNBER; i++) { +- TSMReceivedEntry *e = &p->entrys[i]; +- tsm_free_received_entry (rctl, e); +- }; +- +- p->next = rctl->memory; +- rctl->memory = p; +- +- ret = p->entrys; +- } +- } +- return ret; +-} +- +- +-void +-TSManagerReceive2 (void *handle, TSM_TIMESTAMP timestamp, int size) +-{ +-#define CLEAR_TSM_RENTRY(entry)\ +- do { \ +- (entry)->used = 0; \ +- (entry)->subentry = 0; \ +- (entry)->next = NULL; \ +- } while (0) +- TSManager *tsm = (TSManager *) handle; +- +- TSM_VERBOSE ("receive2 %" TSM_TIME_FORMAT " size %d\n", +- TSM_TIME_ARGS (timestamp), size); +- +- if (tsm) { +- if (size > 0) { +- TSMRecivedCtl *rctl = &tsm->rctl; +- TSMReceivedEntry *e = tsm_new_received_entry (rctl); +- if (e) { +- CLEAR_TSM_RENTRY (e); +- if ((rctl->tail) && (rctl->tail->ts == timestamp)) { +- e->subentry = 1; +- } +- e->ts = timestamp; +- e->size = size; +- if (rctl->tail) { +- rctl->tail->next = e; +- rctl->tail = e; +- } else { +- rctl->head = rctl->tail = e; +- } +- } +- rctl->cnt++; +- } else { +- TSManagerReceive (handle, timestamp); +- } +- } +-} +- +- +-static TSM_TIMESTAMP +-TSManagerGetLastTimeStamp (TSMRecivedCtl * rctl, int size, int use) +-{ +- TSM_TIMESTAMP ts = TSM_TIMESTAMP_NONE; +- TSMReceivedEntry *e; +- while ((size > 0) && (e = rctl->head)) { +- ts = ((e->used) ? (TSM_TIMESTAMP_NONE) : (e->ts)); +- if (use) +- e->used = 1; +- if (size >= e->size) { +- rctl->head = e->next; +- if (rctl->head == NULL) { +- rctl->tail = NULL; +- } else { +- if (rctl->head->subentry) { +- rctl->head->used = e->used; +- } +- } +- size -= e->size; +- rctl->cnt--; +- tsm_free_received_entry (rctl, e); +- } else { +- e->size -= size; +- size = 0; +- } +- } +- return ts; +-} +- +- +-void +-TSManagerFlush2 (void *handle, int size) +-{ +- TSManager *tsm = (TSManager *) handle; +- if (tsm) { +- TSManagerGetLastTimeStamp (&tsm->rctl, size, 0); +- } +- +-} +- +- +-/*====================================================================================== +-FUNCTION: mfw_gst_receive_ts +- +-DESCRIPTION: Check timestamp and do frame dropping if enabled +- +-ARGUMENTS PASSED: pTimeStamp_Object - TimeStamp Manager to handle related timestamp +- timestamp - time stamp of the input buffer which has video data. +- +-RETURN VALUE: None +-PRE-CONDITIONS: None +-POST-CONDITIONS: None +-IMPORTANT NOTES: None +-=======================================================================================*/ +-static void +-_TSManagerReceive (void *handle, TSM_TIMESTAMP timestamp, void *key) +-{ +- TSManager *tsm = (TSManager *) handle; +- +- if (tsm) { +- if (TSM_TS_IS_VALID (timestamp) && (tsm->rx_cnt)) +- tsm->valid_ts_received = 1; +- tsm->rx_cnt++; +- if (tsm->cnt < tsm->ts_buf_size - 1) { +- tsm->cnt++; +- if (tsm->mode == MODE_AI) { +- +- if (TSM_TS_IS_VALID (timestamp)) { +- if (tsm->first_rx) { +- tsm->last_ts_received = timestamp; +- tsm->first_rx = 0; +- } else { +- if (tsm->suspicious_ts) { +- if (timestamp >= tsm->suspicious_ts) { +- tsm->last_ts_received = timestamp; +- } +- tsm->suspicious_ts = 0; +- } +- if ((timestamp > tsm->last_ts_received) +- && (timestamp - tsm->last_ts_received > tsm->discont_threshold)) { +- tsm->suspicious_ts = timestamp; +- timestamp = TSM_TIMESTAMP_NONE; +- } +- } +- } +- +- if (TSM_TS_IS_VALID (timestamp)) // && (TSM_ABS(timestamp, tsm->last_ts_sent)ts_buf[tsm->rx].ts = timestamp; +- tsm->ts_buf[tsm->rx].age = tsm->age + TSM_PLUS_AGE (tsm); +- tsm->ts_buf[tsm->rx].key = key; +- tsm->last_ts_received = timestamp; +-#ifdef DEBUG +- //printf("age should %lld %lld\n", tsm->age, tsm->ts_buf[tsm->rx].age); +- //printf("++++++ distance = %d tx=%d, rx=%d, invalid count=%d\n", TSM_DISTANCE(tsm), tsm->tx, tsm->rx,tsm->invalid_ts_count); +-#endif +- tsm->rx = ((tsm->rx + 1) % tsm->ts_buf_size); +- } else { +- tsm->invalid_ts_count++; +- } +- } else if (tsm->mode == MODE_FIFO) { +- tsm->ts_buf[tsm->rx].ts = timestamp; +- tsm->rx = ((tsm->rx + 1) % tsm->ts_buf_size); +- } +- TSM_LOG ("++Receive %d:%" TSM_TIME_FORMAT +- ", invalid:%d, size:%d key %p\n", tsm->rx_cnt, +- TSM_TIME_ARGS (timestamp), tsm->invalid_ts_count, tsm->cnt, key); +- } else { +- TSM_ERROR ("Too many timestamps recieved!! (cnt=%d)\n", tsm->cnt); +- } +- } +-} +- +- +-void +-TSManagerValid2 (void *handle, int size, void *key) +-{ +- TSManager *tsm = (TSManager *) handle; +- +- TSM_VERBOSE ("valid2 size %d\n", size); +- +- if (tsm) { +- TSM_TIMESTAMP ts; +- ts = TSManagerGetLastTimeStamp (&tsm->rctl, size, 1); +- _TSManagerReceive (tsm, ts, key); +- } +-} +- +- +-void +-TSManagerReceive (void *handle, TSM_TIMESTAMP timestamp) +-{ +- _TSManagerReceive (handle, timestamp, TSM_KEY_NONE); +-} +- +- +-/*====================================================================================== +-FUNCTION: TSManagerSend +- +-DESCRIPTION: Check timestamp and do frame dropping if enabled +- +-ARGUMENTS PASSED: pTimeStamp_Object - TimeStamp Manager to handle related timestamp +- ptimestamp - returned timestamp to use at render +- +-RETURN VALUE: None +-PRE-CONDITIONS: None +-POST-CONDITIONS: None +-IMPORTANT NOTES: None +-=======================================================================================*/ +-static TSM_TIMESTAMP +-_TSManagerSend2 (void *handle, void *key, int send) +-{ +- TSManager *tsm = (TSManager *) handle; +- int i = tsm->tx; +- int index = -1; +- TSM_TIMESTAMP ts0 = 0, tstmp = TSM_TIMESTAMP_NONE; +- unsigned long long age = 0; +- TSM_TIMESTAMP half_interval = TSM_ADAPTIVE_INTERVAL (tsm) >> 1; +- +- if (tsm) { +- if (send) { +- tsm->tx_cnt++; +- } else { +- tsm->cnt++; +- tsm->invalid_ts_count++; +- } +- if (tsm->cnt > 0) { +- if (send) { +- tsm->cnt--; +- } +- if (tsm->mode == MODE_AI) { +- +- if (tsm->first_tx == 0) { +- tstmp = tsm->last_ts_sent + TSM_ADAPTIVE_INTERVAL (tsm); +- } else { +- tstmp = tsm->last_ts_sent; +- } +- +- while (i != tsm->rx) { +- if (index >= 0) { +- if (tsm->ts_buf[i].ts < ts0) { +- ts0 = tsm->ts_buf[i].ts; +- age = tsm->ts_buf[i].age; +- index = i; +- } +- } else { +- ts0 = tsm->ts_buf[i].ts; +- age = tsm->ts_buf[i].age; +- index = i; +- } +- if ((TSM_KEY_IS_VALID (key)) && (key == tsm->ts_buf[i].key)) +- break; +- i = ((i + 1) % tsm->ts_buf_size); +- } +- if (index >= 0) { +- if ((tsm->invalid_ts_count) && (ts0 >= ((tstmp) + half_interval)) +- && (age > tsm->age)) { +- /* use calculated ts0 */ +- if (send) { +- tsm->invalid_ts_count--; +- } +- } else { +- +- if (send) { +- if (index != tsm->tx) { +- tsm->ts_buf[index] = tsm->ts_buf[tsm->tx]; +- } +- tsm->tx = ((tsm->tx + 1) % tsm->ts_buf_size); +- +- } +-#if 0 +- if (ts0 >= ((tstmp) + half_interval)) +- tstmp = tstmp; +- else +- tstmp = ts0; +-#else +- tstmp = ts0; +-#endif +- } +- +- } else { +- if (send) { +- tsm->invalid_ts_count--; +- } +- } +- +- if (tsm->first_tx == 0) { +- +- if (tstmp > tsm->last_ts_sent) { +- ts0 = (tstmp - tsm->last_ts_sent); +- } else { +- ts0 = 0; +- tstmp = tsm->last_ts_sent; +- } +- +- if (ts0 > TSM_ADAPTIVE_INTERVAL (tsm) * 3 / 2) { +- TSM_WARNING ("Jitter1:%" TSM_TIME_FORMAT " %" TSM_TIME_FORMAT "\n", +- TSM_TIME_ARGS (ts0), +- TSM_TIME_ARGS (TSM_ADAPTIVE_INTERVAL (tsm) * 3 / 2)); +- } else if (ts0 == 0) { +- TSM_WARNING ("Jitter:%" TSM_TIME_FORMAT "\n", TSM_TIME_ARGS (ts0)); +- } +- +- if (send) { +- if ((ts0 < TSM_ADAPTIVE_INTERVAL (tsm) * 2) || (tsm->big_cnt > 3)) { +- tsm->big_cnt = 0; +- tsm->dur_history_total -= +- tsm->dur_history_buf[tsm->dur_history_tx]; +- tsm->dur_history_buf[tsm->dur_history_tx] = ts0; +- tsm->dur_history_tx = +- ((tsm->dur_history_tx + 1) % TSM_HISTORY_SIZE); +- tsm->dur_history_total += ts0; +- } else { +- tsm->big_cnt++; +- } +- } +- } +- +- if (send) { +- tsm->last_ts_sent = tstmp; +- tsm->age++; +- tsm->first_tx = 0; +- } +- +- } else if (tsm->mode == MODE_FIFO) { +- tstmp = tsm->ts_buf[tsm->tx].ts; +- if (send) { +- tsm->tx = ((tsm->tx + 1) % tsm->ts_buf_size); +- } +- ts0 = tstmp - tsm->last_ts_sent; +- if (send) { +- tsm->last_ts_sent = tstmp; +- } +- } +- +- if (send) { +- TSM_LOG ("--Send %d:%" TSM_TIME_FORMAT ", int:%" TSM_TIME_FORMAT +- ", avg:%" TSM_TIME_FORMAT " inkey %p\n", tsm->tx_cnt, +- TSM_TIME_ARGS (tstmp), TSM_TIME_ARGS (ts0), +- TSM_TIME_ARGS (TSM_ADAPTIVE_INTERVAL (tsm)), key); +- } +- +- } else { +- if (tsm->valid_ts_received == 0) { +- if (tsm->first_tx) { +- tstmp = tsm->last_ts_sent; +- } else { +- tstmp = tsm->last_ts_sent + TSM_ADAPTIVE_INTERVAL (tsm); +- } +- if (send) { +- tsm->first_tx = 0; +- tsm->last_ts_sent = tstmp; +- } +- } +- TSM_ERROR ("Too many timestamps send!!\n"); +- } +- +- if (send == 0) { +- tsm->cnt--; +- tsm->invalid_ts_count--; +- } +- +- } +- +- return tstmp; +-} +- +- +-TSM_TIMESTAMP +-TSManagerSend2 (void *handle, void *key) +-{ +- return _TSManagerSend2 (handle, key, 1); +-} +- +- +-TSM_TIMESTAMP +-TSManagerQuery2 (void *handle, void *key) +-{ +- return _TSManagerSend2 (handle, key, 0); +-} +- +- +-TSM_TIMESTAMP +-TSManagerSend (void *handle) +-{ +- return TSManagerSend2 (handle, TSM_KEY_NONE); +-} +- +- +-TSM_TIMESTAMP +-TSManagerQuery (void *handle) +-{ +- return TSManagerQuery2 (handle, TSM_KEY_NONE); +-} +- +- +-void +-resyncTSManager (void *handle, TSM_TIMESTAMP synctime, TSMGR_MODE mode) +-{ +- TSManager *tsm = (TSManager *) handle; +- if (tsm) { +- TSMRecivedCtl *rctl = &tsm->rctl; +- TSMReceivedEntry *e = rctl->head; +- +- while ((e = rctl->head)) { +- rctl->head = e->next; +- tsm_free_received_entry (rctl, e); +- }; +- rctl->cnt = 0; +- +- rctl->tail = NULL; +- +- tsm->first_tx = 1; +- tsm->first_rx = 1; +- tsm->suspicious_ts = 0; +- +- if (TSM_TS_IS_VALID (synctime)) +- tsm->last_ts_sent = synctime; +- +- tsm->tx = tsm->rx = 0; +- tsm->invalid_ts_count = 0; +- tsm->mode = mode; +- tsm->age = 0; +- tsm->rx_cnt = tsm->tx_cnt = tsm->cnt = 0; +- tsm->valid_ts_received = 0; +- +- tsm->big_cnt = 0; +- } +-} +- +- +-/*====================================================================================== +-FUNCTION: mfw_gst_init_ts +- +-DESCRIPTION: malloc and initialize timestamp strcture +- +-ARGUMENTS PASSED: ppTimeStamp_Object - pointer of TimeStamp Manager to handle related timestamp +- +-RETURN VALUE: TimeStamp structure pointer +-PRE-CONDITIONS: None +-POST-CONDITIONS: None +-IMPORTANT NOTES: None +-=======================================================================================*/ +-void * +-createTSManager (int ts_buf_size) +-{ +- TSManager *tsm = (TSManager *) malloc (sizeof (TSManager)); +- debug = getenv (debug_env); +- if (debug) { +- debug_level = atoi (debug); +- } +- // printf("debug = %s \n ++++++++++++++++++++++++++++",debug); +- if (tsm) { +- memset (tsm, 0, sizeof (TSManager)); +- if (ts_buf_size <= 0) { +- ts_buf_size = TSM_DEFAULT_TS_BUFFER_SIZE; +- } +- tsm->ts_buf_size = ts_buf_size; +- tsm->ts_buf = malloc (sizeof (TSMControl) * ts_buf_size); +- +- if (tsm->ts_buf == NULL) { +- goto fail; +- } +- +- resyncTSManager (tsm, (TSM_TIMESTAMP) 0, MODE_AI); +- +- tsm->dur_history_tx = 0; +- TSM_BUFFER_SET (tsm->dur_history_buf, TSM_DEFAULT_INTERVAL, +- TSM_HISTORY_SIZE); +- tsm->dur_history_total = TSM_DEFAULT_INTERVAL << TSM_HISTORY_POWER; +- +- tsm->discont_threshold = 10000000000LL; // 10s +- } +- return tsm; +-fail: +- if (tsm) { +- if (tsm->ts_buf) { +- free (tsm->ts_buf); +- } +- free (tsm); +- tsm = NULL; +- } +- return tsm; +-} +- +- +-void +-destroyTSManager (void *handle) +-{ +- TSManager *tsm = (TSManager *) handle; +- if (tsm) { +- TSMRecivedCtl *rctl = &tsm->rctl; +- TSMReceivedEntryMemory *rmem; +- if (tsm->ts_buf) { +- free (tsm->ts_buf); +- } +- +- while ((rmem = rctl->memory)) { +- rctl->memory = rmem->next; +- free (rmem); +- } +- free (tsm); +- tsm = NULL; +- } +-} +- +- +-void +-setTSManagerFrameRate (void *handle, int fps_n, int fps_d) +-//void setTSManagerFrameRate(void * handle, float framerate) +-{ +- TSManager *tsm = (TSManager *) handle; +- TSM_TIMESTAMP ts; +- if ((fps_n > 0) && (fps_d > 0) && (fps_n / fps_d <= 80)) +- ts = TSM_SECOND * fps_d / fps_n; +- else +- ts = TSM_DEFAULT_INTERVAL; +- // TSM_TIMESTAMP ts = TSM_SECOND / framerate; +- +- if (tsm) { +- TSM_BUFFER_SET (tsm->dur_history_buf, ts, TSM_HISTORY_SIZE); +- tsm->dur_history_total = (ts << TSM_HISTORY_POWER); +- if (debug) +- TSM_LOG ("Set frame intrval:%" TSM_TIME_FORMAT "\n", TSM_TIME_ARGS (ts)); +- } +-} +- +- +-TSM_TIMESTAMP +-getTSManagerFrameInterval (void *handle) +-{ +- TSManager *tsm = (TSManager *) handle; +- TSM_TIMESTAMP ts = 0; +- if (tsm) { +- ts = TSM_ADAPTIVE_INTERVAL (tsm); +- } +- return ts; +-} +- +- +-TSM_TIMESTAMP +-getTSManagerPosition (void *handle) +-{ +- TSManager *tsm = (TSManager *) handle; +- TSM_TIMESTAMP ts = 0; +- if (tsm) { +- ts = tsm->last_ts_sent; +- } +- return ts; +-} +- +- +-int +-getTSManagerPreBufferCnt (void *handle) +-{ +- int i = 0; +- TSManager *tsm = (TSManager *) handle; +- if (tsm) { +- i = tsm->rctl.cnt; +- } +- return i; +-} +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h +deleted file mode 100644 +index f5d66c4..0000000 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/mfw_gst_ts.h ++++ /dev/null +@@ -1,170 +0,0 @@ +-/* +- * Copyright (c) 2010-2012, Freescale Semiconductor, Inc. All rights reserved. +- * +- */ +- +-/* +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Library General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This library 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 +- * Library General Public License for more details. +- * +- * You should have received a copy of the GNU Library General Public +- * License along with this library; if not, write to the +- * Free Software Foundation, Inc., 59 Temple Place - Suite 330, +- * Boston, MA 02111-1307, USA. +- */ +- +-/* +- * Module Name: TimeStamp.h +- * +- * Description: include TimeStamp stratege for VPU / SW video decoder plugin +- * +- * Portability: This code is written for Linux OS and Gstreamer +- */ +- +-/* +- * Changelog: +- 11/2/2010 draft version Lyon Wang +- * +- */ +- +-#ifndef _TIMESTAMP_H_ +-#define _TIMESTAMP_H_ +- +- +-/** +- * GST_CLOCK_TIME_NONE: +- * +- * Constant to define an undefined clock time. +- */ +- +-typedef long long TSM_TIMESTAMP; +- +-typedef enum +-{ +- MODE_AI, +- MODE_FIFO, +-} TSMGR_MODE; +- +-#define TSM_TIMESTAMP_NONE ((long long)(-1)) +-#define TSM_KEY_NONE ((void *)0) +- +-/** +- * GST_CLOCK_TIME_IS_VALID: +- * @time: clock time to validate +- * +- * Tests if a given #GstClockTime represents a valid defined time. +- */ +- +-#ifdef __cplusplus +-#define EXTERN +-#else +-#define EXTERN extern +-#endif +- +-#ifdef __cplusplus +-extern "C" +-{ +-#endif +- +-/*! +- * This function receive timestamp into timestamp manager. +- * +- * @param handle handle of timestamp manager. +- * +- * @param timestamp timestamp received +- * +- * @return +- */ +- EXTERN void TSManagerReceive (void *handle, TSM_TIMESTAMP timestamp); +- +- EXTERN void TSManagerReceive2 (void *handle, TSM_TIMESTAMP timestamp, +- int size); +- +- EXTERN void TSManagerFlush2 (void *handle, int size); +- +- EXTERN void TSManagerValid2 (void *handle, int size, void *key); +- +-/*! +- * This function send the timestamp for next output frame. +- * +- * @param handle handle of timestamp manager. +- * +- * @return timestamp for next output frame. +- */ +- EXTERN TSM_TIMESTAMP TSManagerSend (void *handle); +- +- EXTERN TSM_TIMESTAMP TSManagerSend2 (void *handle, void *key); +- +- EXTERN TSM_TIMESTAMP TSManagerQuery2 (void *handle, void *key); +- +- EXTERN TSM_TIMESTAMP TSManagerQuery (void *handle); +-/*! +- * This function resync timestamp handler when reset and seek +- * +- * @param handle handle of timestamp manager. +- * +- * @param synctime the postion time needed to set, if value invalid, position keeps original +- * +- * @param mode playing mode (AI or FIFO) +- * +- * @return +- */ +- EXTERN void resyncTSManager (void *handle, TSM_TIMESTAMP synctime, +- TSMGR_MODE mode); +-/*! +- * This function create and reset timestamp handler +- * +- * @param ts_buf_size time stamp queue buffer size +- * +- * @return +- */ +- EXTERN void *createTSManager (int ts_buf_size); +-/*! +- * This function destory timestamp handler +- * +- * @param handle handle of timestamp manager. +- * +- * @return +- */ +- EXTERN void destroyTSManager (void *handle); +-/*! +- * This function set history buffer frame interval by fps_n and fps_d +- * +- * @param handle handle of timestamp manager. +- * +- * @param framerate the framerate to be set +- * +- * @return +- */ +- EXTERN void setTSManagerFrameRate (void *handle, int fps_n, int fps_d); +-//EXTERN void setTSManagerFrameRate(void * handle, float framerate); +-/*! +- * This function set the current calculated Frame Interval +- * +- * @param handle handle of timestamp manager. +- * +- * @return +- */ +- EXTERN TSM_TIMESTAMP getTSManagerFrameInterval (void *handle); +-/*! +- * This function get the current time stamp postion +- * +- * @param handle handle of timestamp manager. +- * +- * @return +- */ +- EXTERN TSM_TIMESTAMP getTSManagerPosition (void *handle); +- EXTERN int getTSManagerPreBufferCnt (void *handle); +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif /*_TIMESTAMP_H_ */ +-- +1.9.3 + + +From e3fb12fc3681798b072103b67c46cc145c250366 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Wed, 19 Feb 2014 12:35:40 +0100 +Subject: [PATCH 17/56] FIX: [imx] cosmetics + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 73 ++++++++++------------ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 2 +- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 8 +-- + xbmc/windowing/egl/EGLNativeTypeIMX.h | 4 +- + 4 files changed, 39 insertions(+), 48 deletions(-) + mode change 100644 => 100755 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp + mode change 100644 => 100755 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h + mode change 100644 => 100755 xbmc/windowing/egl/EGLNativeTypeIMX.cpp + mode change 100644 => 100755 xbmc/windowing/egl/EGLNativeTypeIMX.h + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +old mode 100644 +new mode 100755 +index 13be3fc..e7e472b +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -97,8 +97,7 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + + int CDVDVideoCodecIMX::VpuFindBuffer(void *frameAddr) + { +- int i; +- for (i=0; i1) + { + ptr=(unsigned char*)Align(ptr,nAlign); + ptrVirt=(unsigned char*)Align(ptrVirt,nAlign); + } + +- /* fill stride info */ ++ // fill stride info + m_vpuFrameBuffers[i].nStrideY=yStride; + m_vpuFrameBuffers[i].nStrideC=uvStride; + +- /* fill phy addr*/ ++ // 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 */ ++ // fill virt addr + m_vpuFrameBuffers[i].pbufVirtY=ptrVirt; + m_vpuFrameBuffers[i].pbufVirtCb=ptrVirt+ySize; + m_vpuFrameBuffers[i].pbufVirtCr=0; +@@ -363,10 +360,9 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + } + if (m_hints.extrasize) + { +- unsigned int i; + char buf[4096]; + +- for (i = 0; i < m_hints.extrasize; i++) ++ for (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); + } +@@ -429,19 +425,19 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + m_pFormatName = "iMX-vp8"; + break; + case CODEC_ID_MSMPEG4V3: +- m_decOpenParam.CodecFormat = VPU_V_XVID; /* VPU_V_DIVX3 */ ++ m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX3 + m_pFormatName = "iMX-divx3"; + 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_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_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX56 + m_pFormatName = "iMX-divx5"; + break; + case _4CC('X','V','I','D'): +@@ -468,10 +464,9 @@ void CDVDVideoCodecIMX::Dispose(void) + { + VpuDecRetCode ret; + bool VPU_loaded = m_vpuHandle; +- int i; + + // Invalidate output buffers to prevent the renderer from mapping this memory +- for (i=0; iInvalidate(&m_vpuHandle); + SAFE_RELEASE(m_outputBuffers[i]); +@@ -530,7 +525,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + VpuDecFrameLengthInfo frameLengthInfo; + VpuBufferNode inData; + VpuDecRetCode ret; +- int decRet = 0, i; ++ int decRet = 0; + int retStatus = 0; + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; +@@ -549,7 +544,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + return VC_ERROR; + } + +- for (i=0; i < m_vpuFrameBufferNum; i++) ++ for (int i=0; i < m_vpuFrameBufferNum; i++) + { + if (m_outputBuffers[i]->Rendered()) + { +@@ -589,7 +584,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + inData.nSize = demuxer_bytes; + inData.pPhyAddr = NULL; + inData.pVirAddr = demuxer_content; +- /* FIXME TODO VP8 & DivX3 require specific sCodecData values */ ++ // 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)) +@@ -621,7 +616,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } + + if (decRet & VPU_DEC_INIT_OK) +- /* VPU decoding init OK : We can retrieve stream info */ ++ // VPU decoding init OK : We can retrieve stream info + { + ret = VPU_DecGetInitialInfo(m_vpuHandle, &m_initInfo); + if (ret == VPU_DEC_RET_SUCCESS) +@@ -650,7 +645,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + CLog::Log(LOGERROR, "%s - VPU get initial info failed (%d).\n", __FUNCTION__, ret); + goto out_error; + } +- }//VPU_DEC_INIT_OK ++ } //VPU_DEC_INIT_OK + + if (decRet & VPU_DEC_ONE_FRM_CONSUMED) + { +@@ -665,24 +660,20 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + if (idx != -1) + { + if (pts != DVD_NOPTS_VALUE) +- { + m_outputBuffers[idx]->SetPts(pts); +- } + else if (dts != DVD_NOPTS_VALUE) +- { + m_outputBuffers[idx]->SetPts(dts); +- } + } + else + { + CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); + } + } +- }//VPU_DEC_ONE_FRM_CONSUMED ++ } //VPU_DEC_ONE_FRM_CONSUMED + + if ((decRet & VPU_DEC_OUTPUT_DIS) || + (decRet & VPU_DEC_OUTPUT_MOSAIC_DIS)) +- /* Frame ready to be displayed */ ++ // Frame ready to be displayed + { + if (retStatus & VC_PICTURE) + CLog::Log(LOGERROR, "%s - Second picture in the same decode call !\n", __FUNCTION__); +@@ -739,9 +730,9 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + if (!(decRet & VPU_DEC_OUTPUT_DIS) && + (inData.nSize != 0)) + { +- /* 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 +- */ ++ // 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; + retry = true; +@@ -766,18 +757,18 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + + void CDVDVideoCodecIMX::Reset() + { +- int ret, i; ++ int ret; + + CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); + +- /* We have to resync timestamp manager */ ++ // We have to resync timestamp manager + m_tsSyncRequired = true; + +- /* Invalidate all buffers */ +- for(i = 0; i < m_vpuFrameBufferNum; i++) ++ // Invalidate all buffers ++ for(int i=0; i < m_vpuFrameBufferNum; i++) + m_outputBuffers[i]->Invalidate(&m_vpuHandle); + +- /* Flush VPU */ ++ // Flush VPU + ret = VPU_DecFlushAll(m_vpuHandle); + if (ret != VPU_DEC_RET_SUCCESS) + { +@@ -851,10 +842,10 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + 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 !) +- */ ++ // 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; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +old mode 100644 +new mode 100755 +index c4418fe..ac0345f +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -31,7 +31,7 @@ + //#define IMX_PROFILE + //#define TRACE_FRAMES + +-/* FIXME TODO Develop real proper CVPUBuffer class */ ++// FIXME TODO Develop real proper CVPUBuffer class + #define VPU_DEC_MAX_NUM_MEM_NUM 20 + typedef struct + { +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +old mode 100644 +new mode 100755 +index b44d4b8..bd83877 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -61,14 +61,14 @@ void CEGLNativeTypeIMX::Initialize() + CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); + return; + } +- /* Store screen info */ ++ // Store screen info + if (ioctl(fd, FBIOGET_VSCREENINFO, &m_screeninfo) != 0) + { + CLog::Log(LOGERROR, "%s - Error while querying frame buffer.\n", __FUNCTION__); + return; + } + +- /* Unblank the fbs */ ++ // Unblank the fbs + if (ioctl(fd, FBIOBLANK, 0) < 0) + { + CLog::Log(LOGERROR, "%s - Error while unblanking fb0.\n", __FUNCTION__); +@@ -93,7 +93,7 @@ void CEGLNativeTypeIMX::Destroy() + } + + ioctl( fd, FBIOGET_FSCREENINFO, &fixed_info); +- /* Black fb0 */ ++ // Black fb0 + fb_buffer = mmap(NULL, fixed_info.smem_len, PROT_WRITE, MAP_SHARED, fd, 0); + if (fb_buffer == MAP_FAILED) + { +@@ -112,7 +112,7 @@ void CEGLNativeTypeIMX::Destroy() + + bool CEGLNativeTypeIMX::CreateNativeDisplay() + { +- /* EGL will be rendered on fb0 */ ++ // EGL will be rendered on fb0 + m_display = fbGetDisplayByIndex(0); + m_nativeDisplay = &m_display; + return true; +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.h b/xbmc/windowing/egl/EGLNativeTypeIMX.h +old mode 100644 +new mode 100755 +index 61d5833..b9162ee +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.h ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.h +@@ -28,11 +28,11 @@ class CEGLNativeTypeIMX : public CEGLNativeType + public: + CEGLNativeTypeIMX(); + virtual ~CEGLNativeTypeIMX(); +- virtual std::string GetNativeName() const { return "iMX"; }; ++ virtual std::string GetNativeName() const { return "iMX"; } + virtual bool CheckCompatibility(); + virtual void Initialize(); + virtual void Destroy(); +- virtual int GetQuirks() { return EGL_QUIRK_NONE; }; ++ virtual int GetQuirks() { return EGL_QUIRK_NONE; } + + virtual bool CreateNativeDisplay(); + virtual bool CreateNativeWindow(); +-- +1.9.3 + + +From 34643579eebb603ee08b1b660b65bdba074cac57 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Wed, 19 Feb 2014 12:41:34 +0100 +Subject: [PATCH 18/56] FIX: [imx] avoid potential segfault + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + mode change 100644 => 100755 xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +old mode 100644 +new mode 100755 +index f731beb..4c286f8 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -2725,14 +2725,12 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + glBindTexture(m_textureTarget, 0); + + plane.flipindex = m_buffers[index].flipindex; +- } ++ plane.texwidth = codecinfo->iWidth; ++ plane.texheight = codecinfo->iHeight; + +- YUVFIELDS &fields = m_buffers[index].fields; +- YUVPLANE &plane = fields[0][0]; +- plane.texwidth = codecinfo->iWidth; +- plane.texheight = codecinfo->iHeight; ++ CalculateTextureSourceRects(index, 1); ++ } + +- CalculateTextureSourceRects(index, 1); + #endif + } + void CLinuxRendererGLES::DeleteIMXMAPTexture(int index) +-- +1.9.3 + + +From 67d06c9dbf33d628471f94889da77c0d56649118 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Wed, 19 Feb 2014 13:00:37 +0100 +Subject: [PATCH 19/56] FIX: [imx] CDVDVideoCodecIMXBuffer optimizations + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 37 ++++++++-------------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 3 +- + 2 files changed, 15 insertions(+), 25 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index e7e472b..2b9002a 100755 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -468,7 +468,7 @@ void CDVDVideoCodecIMX::Dispose(void) + // Invalidate output buffers to prevent the renderer from mapping this memory + for (int i=0; iInvalidate(&m_vpuHandle); ++ m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle); + SAFE_RELEASE(m_outputBuffers[i]); + } + +@@ -548,7 +548,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + if (m_outputBuffers[i]->Rendered()) + { +- ret = m_outputBuffers[i]->ClearDisplay(&m_vpuHandle); ++ 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); +@@ -766,7 +766,7 @@ void CDVDVideoCodecIMX::Reset() + + // Invalidate all buffers + for(int i=0; i < m_vpuFrameBufferNum; i++) +- m_outputBuffers[i]->Invalidate(&m_vpuHandle); ++ m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle); + + // Flush VPU + ret = VPU_DecFlushAll(m_vpuHandle); +@@ -913,24 +913,6 @@ bool CDVDVideoCodecIMXBuffer::IsValid() + return m_frameBuffer != NULL; + } + +-void CDVDVideoCodecIMXBuffer::Invalidate(VpuDecHandle *handle) +-{ +- CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); +-#ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "I %02d\n", m_idx); +-#endif +- if((m_frameBuffer != NULL) && *handle) +- { +- VpuDecRetCode 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); +- } +- +- m_frameBuffer = NULL; +- m_rendered = false; +- m_pts = DVD_NOPTS_VALUE; +-} +- + bool CDVDVideoCodecIMXBuffer::Rendered() + { + return m_rendered; +@@ -938,13 +920,22 @@ bool CDVDVideoCodecIMXBuffer::Rendered() + + void CDVDVideoCodecIMXBuffer::Queue(VpuFrameBuffer *buffer) + { ++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); + m_frameBuffer = buffer; + m_rendered = false; + } + +-VpuDecRetCode CDVDVideoCodecIMXBuffer::ClearDisplay(VpuDecHandle *handle) ++VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + { +- VpuDecRetCode ret = VPU_DecOutFrameDisplayed(*handle, m_frameBuffer); ++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++ 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\n", m_idx); + #endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index ac0345f..1b9a2b8 100755 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -61,10 +61,9 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + virtual long Release(); + virtual bool IsValid(); + +- void Invalidate(VpuDecHandle *handle); + bool Rendered(); + void Queue(VpuFrameBuffer *buffer); +- VpuDecRetCode ClearDisplay(VpuDecHandle *handle); ++ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); + void SetPts(double pts); + double GetPts(void) const; + +-- +1.9.3 + + +From 0291838e8bc0bcf4db8b21f30febece36b426ec1 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Fri, 21 Feb 2014 07:04:02 +0000 +Subject: [PATCH 20/56] chmod -x + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 0 + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 0 + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 0 + 3 files changed, 0 insertions(+), 0 deletions(-) + mode change 100755 => 100644 xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp + mode change 100755 => 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp + mode change 100755 => 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +old mode 100755 +new mode 100644 +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +old mode 100755 +new mode 100644 +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +old mode 100755 +new mode 100644 +-- +1.9.3 + + +From 22048a486c7c42a72817be07fd11e4e348e7a5cf Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Thu, 20 Feb 2014 17:42:39 +0100 +Subject: [PATCH 21/56] ADD: [imx] dynamic resolutions / refresh rates + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 199 ++++++++++++++++++++++---------- + xbmc/windowing/egl/EGLNativeTypeIMX.h | 14 +-- + 2 files changed, 144 insertions(+), 69 deletions(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index bd83877..3e3e45e 100755 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -27,6 +27,7 @@ + #include + #include + #include "utils/log.h" ++#include "utils/RegExp.h" + #include "utils/StringUtils.h" + #include "guilib/gui3d.h" + +@@ -36,13 +37,12 @@ CEGLNativeTypeIMX::CEGLNativeTypeIMX() + + CEGLNativeTypeIMX::~CEGLNativeTypeIMX() + { +-} ++} + + bool CEGLNativeTypeIMX::CheckCompatibility() + { +- char name[256] = {0}; +- get_sysfs_str("/sys/class/graphics/fb0/device/modalias", name, 255); +- CStdString strName = name; ++ std::string strName; ++ get_sysfs_str("/sys/class/graphics/fb0/device/modalias", strName); + StringUtils::Trim(strName); + if (strName == "platform:mxc_sdc_fb") + return true; +@@ -50,32 +50,38 @@ bool CEGLNativeTypeIMX::CheckCompatibility() + } + + void CEGLNativeTypeIMX::Initialize() +-{ +- struct mxcfb_gbl_alpha alpha; ++{ + int fd; + +- + fd = open("/dev/fb0",O_RDWR); + if (fd < 0) + { + CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); + return; + } +- // Store screen info +- if (ioctl(fd, FBIOGET_VSCREENINFO, &m_screeninfo) != 0) +- { +- CLog::Log(LOGERROR, "%s - Error while querying frame buffer.\n", __FUNCTION__); +- return; +- } +- +- // Unblank the fbs ++ ++ // 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; + } + +@@ -90,23 +96,23 @@ void CEGLNativeTypeIMX::Destroy() + { + CLog::Log(LOGERROR, "%s - Error while opening /dev/fb0.\n", __FUNCTION__); + return; +- } +- +- ioctl( fd, FBIOGET_FSCREENINFO, &fixed_info); ++ } ++ ++ 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 ++ else + { + memset(fb_buffer, 0x0, fixed_info.smem_len); + munmap(fb_buffer, fixed_info.smem_len); + } +- +- close(fd); +- ++ ++ close(fd); ++ + return; + } + +@@ -120,15 +126,17 @@ bool CEGLNativeTypeIMX::CreateNativeDisplay() + + bool CEGLNativeTypeIMX::CreateNativeWindow() + { +- m_window = fbCreateWindow(m_display, 0, 0, m_screeninfo.xres, m_screeninfo.yres); ++ 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; + } +@@ -137,67 +145,76 @@ 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 + { +- double drate = 0, hrate = 0, vrate = 0; +- if (!res) ++ 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; + +- drate = 1e12 / m_screeninfo.pixclock; +- hrate = drate / (m_screeninfo.left_margin + m_screeninfo.xres + m_screeninfo.right_margin + m_screeninfo.hsync_len); +- vrate = hrate / (m_screeninfo.upper_margin + m_screeninfo.yres + m_screeninfo.lower_margin + m_screeninfo.vsync_len); ++ DestroyNativeWindow(); ++ DestroyNativeDisplay(); + +- res->iWidth = m_screeninfo.xres; +- res->iHeight = m_screeninfo.yres; +- res->iScreenWidth = res->iWidth; +- res->iScreenHeight = res->iHeight; +- res->fRefreshRate = lrint(vrate); +- res->dwFlags= D3DPRESENTFLAG_PROGRESSIVE; +- 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" : ""); ++ set_sysfs_str("/sys/class/graphics/fb0/mode", res.strId); + +- return res->iWidth > 0 && res->iHeight> 0; +-} ++ CreateNativeDisplay(); + +-bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res) +-{ +- return false; ++ CLog::Log(LOGDEBUG, "%s: %s",__FUNCTION__, res.strId.c_str()); ++ return true; + } + + bool CEGLNativeTypeIMX::ProbeResolutions(std::vector &resolutions) + { ++ if (m_readonly) ++ return false; ++ ++ std::string valstr; ++ get_sysfs_str("/sys/class/graphics/fb0/modes", valstr); ++ std::vector probe_str; ++ StringUtils::SplitString(valstr, "\n", probe_str); ++ ++ resolutions.clear(); + RESOLUTION_INFO res; +- bool ret = false; +- ret = GetNativeResolution(&res); +- if (ret && res.iWidth > 1 && res.iHeight > 1) ++ for (size_t i = 0; i < probe_str.size(); i++) + { +- resolutions.push_back(res); +- return true; ++ if(!StringUtils::StartsWith(probe_str[i], "S:")) ++ continue; ++ if(ModeToResolution(probe_str[i], &res)) ++ resolutions.push_back(res); + } +- return false; ++ return resolutions.size() > 0; + } + + bool CEGLNativeTypeIMX::GetPreferredResolution(RESOLUTION_INFO *res) const + { +- return false; ++ return GetNativeResolution(res); + } + + bool CEGLNativeTypeIMX::ShowWindow(bool show) +@@ -206,20 +223,80 @@ bool CEGLNativeTypeIMX::ShowWindow(bool show) + return false; + } + +-int CEGLNativeTypeIMX::get_sysfs_str(const char *path, char *valstr, const int size) const ++int CEGLNativeTypeIMX::get_sysfs_str(std::string path, std::string& valstr) const + { +- int fd = open(path, O_RDONLY); ++ int len; ++ char buf[256] = {0}; ++ ++ int fd = open(path.c_str(), O_RDONLY); + if (fd >= 0) + { +- int len = read(fd, valstr, size - 1); +- if (len != -1 ) +- valstr[len] = '\0'; ++ while ((len = read(fd, buf, 255)) > 0) ++ valstr.append(buf, len); + close(fd); + } + else + { +- sprintf(valstr, "%s", "fail"); ++ 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 --git a/xbmc/windowing/egl/EGLNativeTypeIMX.h b/xbmc/windowing/egl/EGLNativeTypeIMX.h +index b9162ee..df7b3b7 100755 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.h ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.h +@@ -48,15 +48,13 @@ class CEGLNativeTypeIMX : public CEGLNativeType + virtual bool GetPreferredResolution(RESOLUTION_INFO *res) const; + + virtual bool ShowWindow(bool show); +- +- protected: +- int get_sysfs_str(const char *path, char *valstr, const int size) const; +- bool ModeToResolution(const char *mode, RESOLUTION_INFO *res) const; +- +- EGLNativeDisplayType m_display; +- EGLNativeWindowType m_window; + + protected: +- struct fb_var_screeninfo m_screeninfo; ++ 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; + }; +-- +1.9.3 + + +From aef2e65a9941d0be6e8bad5329cac089d4be216e Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Fri, 21 Feb 2014 13:02:34 +0100 +Subject: [PATCH 22/56] Merge pull request #9 + +FIX: [imx] runtime vivante egl extensions +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 4c286f8..1c2fc86 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -26,9 +26,6 @@ + #endif + + #if HAS_GLES == 2 +-#ifdef HAS_IMXVPU +-#define GL_GLEXT_PROTOTYPES +-#endif + #include "system_gl.h" + + #include +@@ -83,9 +80,12 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + #endif + + #ifdef HAS_IMXVPU +-// GLES extension functions +-#include +-#include ++#include "windowing/egl/EGLWrapper.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) +@@ -163,6 +163,12 @@ CLinuxRendererGLES::CLinuxRendererGLES() + 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() +-- +1.9.3 + + +From 505f31ea096e74e41dc97286b6ff60eeb5ab4580 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Mon, 24 Feb 2014 11:18:51 +0100 +Subject: [PATCH 23/56] FIX: cross-complation + +--- + xbmc/cores/VideoRenderers/RenderManager.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp +index 836bcd1..60b9118 100644 +--- a/xbmc/cores/VideoRenderers/RenderManager.cpp ++++ b/xbmc/cores/VideoRenderers/RenderManager.cpp +@@ -930,8 +930,10 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic) + 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); + +-- +1.9.3 + + +From ed7cb7eca920a8d7c8987092e8fc843165bd905e Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Mon, 24 Feb 2014 22:55:58 +0100 +Subject: [PATCH 24/56] Fix mode (remove x) on EGLNativeTypeIMX.* files + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 0 + xbmc/windowing/egl/EGLNativeTypeIMX.h | 0 + 2 files changed, 0 insertions(+), 0 deletions(-) + mode change 100755 => 100644 xbmc/windowing/egl/EGLNativeTypeIMX.cpp + mode change 100755 => 100644 xbmc/windowing/egl/EGLNativeTypeIMX.h + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +old mode 100755 +new mode 100644 +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.h b/xbmc/windowing/egl/EGLNativeTypeIMX.h +old mode 100755 +new mode 100644 +-- +1.9.3 + + +From a4f319e55e9ab66e14bd6f1c8372d2d9156e6ffc Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Fri, 21 Feb 2014 16:48:09 +0100 +Subject: [PATCH 25/56] CHG: [imx] force vsync depending on FB_MULTI_BUFFER + value + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 3e3e45e..3d32705 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -29,7 +29,9 @@ + #include "utils/log.h" + #include "utils/RegExp.h" + #include "utils/StringUtils.h" ++#include "utils/Environment.h" + #include "guilib/gui3d.h" ++#include "windowing/WindowingFactory.h" + + CEGLNativeTypeIMX::CEGLNativeTypeIMX() + { +@@ -118,6 +120,9 @@ void CEGLNativeTypeIMX::Destroy() + + 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; +@@ -219,7 +224,12 @@ bool CEGLNativeTypeIMX::GetPreferredResolution(RESOLUTION_INFO *res) const + + bool CEGLNativeTypeIMX::ShowWindow(bool show) + { +- // CLog::Log(LOGERROR, "%s - call CEGLNativeTypeIMX::ShowWindow with %d.\n", __FUNCTION__, 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; + } + +-- +1.9.3 + + +From 76b8499b7ea9ed4295e23ebb46355d54957d9f04 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Wed, 26 Feb 2014 18:37:05 +0100 +Subject: [PATCH 26/56] FIX: [imx] drop decoder frames which are returned with + flag VPU_DEC_OUTPUT_MOSAIC_DIS set + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 31 ++++++++++++++++++++-- + 1 file changed, 29 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 2b9002a..c85bd8a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -671,8 +671,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + } + } //VPU_DEC_ONE_FRM_CONSUMED + +- if ((decRet & VPU_DEC_OUTPUT_DIS) || +- (decRet & VPU_DEC_OUTPUT_MOSAIC_DIS)) ++ if (decRet & VPU_DEC_OUTPUT_DIS) + // Frame ready to be displayed + { + if (retStatus & VC_PICTURE) +@@ -687,6 +686,34 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + 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; ++ } ++ ++ // Release associated pts ++ idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); ++ if (idx != -1) ++ m_outputBuffers[idx]->SetPts(DVD_NOPTS_VALUE); ++ else ++ CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); ++ ++ // 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__); +-- +1.9.3 + + +From 8bf8bfdf4a66b1c6129d8d3509bf80d7c0c864bc Mon Sep 17 00:00:00 2001 +From: smallint +Date: Thu, 27 Feb 2014 07:26:21 +0000 +Subject: [PATCH 27/56] FIX: [imx] removed unnecessary block that releases an + associated pts + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index c85bd8a..46ddaac 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -698,13 +698,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + goto out_error; + } + +- // Release associated pts +- idx = VpuFindBuffer(m_frameInfo.pDisplayFrameBuf->pbufY); +- if (idx != -1) +- m_outputBuffers[idx]->SetPts(DVD_NOPTS_VALUE); +- else +- CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); +- + // Display frame + ret = VPU_DecOutFrameDisplayed(m_vpuHandle, m_frameInfo.pDisplayFrameBuf); + if(ret != VPU_DEC_RET_SUCCESS) +-- +1.9.3 + + +From 1af4d8af5dc45d4e8b4c99de22b473e7c3f1b3f1 Mon Sep 17 00:00:00 2001 +From: "Chris \"koying\" Browet" +Date: Thu, 27 Feb 2014 09:49:49 +0000 +Subject: [PATCH 28/56] FIX: [imx] Do not force resolution if the same as + current + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 3d32705..729fe56 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -34,6 +34,8 @@ + #include "windowing/WindowingFactory.h" + + CEGLNativeTypeIMX::CEGLNativeTypeIMX() ++ : m_display(NULL) ++ , m_window(NULL) + { + } + +@@ -184,6 +186,11 @@ 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(); + +-- +1.9.3 + + +From 01b52f21f378ce8d9cfe14fb47e9655348783a43 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Thu, 27 Feb 2014 11:58:31 +0100 +Subject: [PATCH 29/56] FIX: [imx] dynamic allocation of buffer array + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 68 +++++++++++++--------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 22 ++++--- + 2 files changed, 53 insertions(+), 37 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 46ddaac..d0d035a 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -48,7 +48,7 @@ CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock; + bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + { + int i, size; +- unsigned char * ptr; ++ void* ptr; + VpuMemDesc vpuMem; + VpuDecRetCode ret; + +@@ -57,7 +57,7 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + size = pMemBlock->MemSubBlock[i].nAlignment + pMemBlock->MemSubBlock[i].nSize; + if (pMemBlock->MemSubBlock[i].MemType == VPU_MEM_VIRT) + { // Allocate standard virtual memory +- ptr = (unsigned char *)malloc(size); ++ ptr = malloc(size); + if(ptr == NULL) + { + CLog::Log(LOGERROR, "%s - Unable to malloc %d bytes.\n", __FUNCTION__, size); +@@ -65,8 +65,9 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + } + pMemBlock->MemSubBlock[i].pVirtAddr = (unsigned char*)Align(ptr, pMemBlock->MemSubBlock[i].nAlignment); + +- m_decMemInfo.virtMem[m_decMemInfo.nVirtNum] = (unsigned int)ptr; + 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 +@@ -80,11 +81,12 @@ bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) + 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.phyMem_phyAddr[m_decMemInfo.nPhyNum] = (unsigned int)vpuMem.nPhyAddr; +- m_decMemInfo.phyMem_virtAddr[m_decMemInfo.nPhyNum] = (unsigned int)vpuMem.nVirtAddr; +- m_decMemInfo.phyMem_cpuAddr[m_decMemInfo.nPhyNum] = (unsigned int)vpuMem.nCpuAddr; +- m_decMemInfo.phyMem_size[m_decMemInfo.nPhyNum] = size; + 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; + } + } + +@@ -111,29 +113,39 @@ bool CDVDVideoCodecIMX::VpuFreeBuffers(void) + VpuDecRetCode vpuRet; + bool ret = true; + +- //free virtual mem +- for(int i=0; i +Date: Sat, 1 Mar 2014 07:52:01 +0100 +Subject: [PATCH 30/56] fix CheckCompatibility for newer kernel + +on newer kernel (3.10.30), + cat /sys/class/graphics/fb0/device/modalias returns "platform:mxc_sdc_fb.28" +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 729fe56..65063e9 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -46,9 +46,11 @@ CEGLNativeTypeIMX::~CEGLNativeTypeIMX() + bool CEGLNativeTypeIMX::CheckCompatibility() + { + std::string strName; ++ std::string str2 ("mxc"); + get_sysfs_str("/sys/class/graphics/fb0/device/modalias", strName); + StringUtils::Trim(strName); +- if (strName == "platform:mxc_sdc_fb") ++ size_t found = strName.find(str2); ++ if (found!=std::string::npos) + return true; + return false; + } +-- +1.9.3 + + +From f56913c9feb4687d0be4d5ce4bb750d730ce31a0 Mon Sep 17 00:00:00 2001 +From: Chris Browet +Date: Sat, 1 Mar 2014 09:06:02 +0100 +Subject: [PATCH 31/56] fixup: remove obsolete comment + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 139d918..d71e975 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -31,7 +31,6 @@ + //#define IMX_PROFILE + //#define TRACE_FRAMES + +-// FIXME TODO Develop real proper CVPUBuffer class + class CDecMemInfo + { + public: +-- +1.9.3 + + +From ad1b3caa51d043beeb937864f87b8bce62edfd3a Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Sat, 1 Mar 2014 09:32:24 +0100 +Subject: [PATCH 32/56] FIX: [imx] force mod 16 output frame size + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index d0d035a..8d9a5e6 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -695,6 +695,11 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + 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 + +-- +1.9.3 + + +From 79703ebce98ce2a31f20c3dfad2af11dcd389008 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Sat, 1 Mar 2014 10:23:37 +0100 +Subject: [PATCH 33/56] [imx] Add IPU hardware deinterlacing support + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 3 +- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 457 +++++++++++++++++++-- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 106 ++++- + 3 files changed, 516 insertions(+), 50 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 1c2fc86..980c1a3 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -2724,8 +2724,9 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + 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 **)(&codecinfo->data[0]), &physical); ++ (GLvoid **)&virt, &physical); + glTexDirectInvalidateVIV(m_textureTarget); + + glBindTexture(m_textureTarget, 0); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 8d9a5e6..233e765 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -1,4 +1,4 @@ +-/* ++/* + * Copyright (C) 2010-2013 Team XBMC + * http://www.xbmc.org + * +@@ -18,15 +18,16 @@ + * + */ + +-#include + #include "DVDVideoCodecIMX.h" + +-#include + #include ++#include + #include + #include + #include + #include ++#include ++#include + #include "threads/SingleLock.h" + #include "utils/log.h" + #include "DVDClock.h" +@@ -38,11 +39,13 @@ + #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)) +-#define min(a, b) (adata[1] ++#define GET_VIRT_ADDR(buf) (buf)->data[0] ++ + // 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 = IMX_MAX_QUEUE_SIZE + 6; ++const int CDVDVideoCodecIMX::m_extraVpuBuffers = 6; + CCriticalSection CDVDVideoCodecIMX::m_codecBufferLock; + + bool CDVDVideoCodecIMX::VpuAllocBuffers(VpuMemInfo *pMemBlock) +@@ -316,19 +319,37 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + #endif + } + ++ if (m_initInfo.nInterlace && (m_modeDeinterlace>0)) ++ { ++ if ((m_initInfo.nPicWidth>1024) || (m_initInfo.nPicHeight>1024)) ++ { ++ CLog::Log(LOGNOTICE, "IMX: Disable hardware deinterlacing for HD playback\n"); ++ m_modeDeinterlace = 0; ++ } ++ else ++ { ++ 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"); ++ m_modeDeinterlace = 0; ++ } ++ } ++ } ++ else ++ m_modeDeinterlace = 0; ++ + return true; + } + + CDVDVideoCodecIMX::CDVDVideoCodecIMX() + { +- m_vpuHandle = 0; + m_pFormatName = "iMX-xxx"; + m_vpuHandle = 0; + m_vpuFrameBuffers = NULL; + m_outputBuffers = NULL; + m_extraMem = NULL; + m_vpuFrameBufferNum = 0; +- m_tsSyncRequired = true; + m_dropState = false; + m_convert_bitstream = false; + m_frameCounter = 0; +@@ -337,6 +358,10 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + { + m_usePTS = false; + } ++ m_modeDeinterlace = 1; // Default is high motion if requested ++ const char *deintEntry = getenv("IMX_DEINT_MOTION"); ++ if (deintEntry != NULL) ++ m_modeDeinterlace = atoi(deintEntry); + m_converter = NULL; + m_convert_bitstream = false; + } +@@ -499,6 +524,9 @@ void CDVDVideoCodecIMX::Dispose(void) + m_vpuHandle = 0; + } + ++ m_frameCounter = 0; ++ m_deinterlacer.Close(); ++ + // Clear memory + if (m_outputBuffers != NULL) + { +@@ -542,6 +570,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; + bool retry = false; ++ bool frameConsumed = false; + int idx; + + #ifdef IMX_PROFILE +@@ -681,6 +710,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); + } + } ++ frameConsumed = true; + } //VPU_DEC_ONE_FRM_CONSUMED + + if (decRet & VPU_DEC_OUTPUT_DIS) +@@ -798,13 +828,13 @@ void CDVDVideoCodecIMX::Reset() + + CLog::Log(LOGDEBUG, "%s - called\n", __FUNCTION__); + +- // We have to resync timestamp manager +- m_tsSyncRequired = true; +- + // Invalidate all buffers + for(int i=0; i < m_vpuFrameBufferNum; i++) + m_outputBuffers[i]->ReleaseFramebuffer(&m_vpuHandle); + ++ m_frameCounter = 0; ++ m_deinterlacer.Reset(); ++ + // Flush VPU + ret = VPU_DecFlushAll(m_vpuHandle); + if (ret != VPU_DEC_RET_SUCCESS) +@@ -831,6 +861,7 @@ bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) + + bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + { ++ m_frameCounter++; + pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED; + if (m_dropState) + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; +@@ -849,24 +880,28 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + if (idx != -1) + { + CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; ++ CDVDVideoCodecIPUBuffer *ipuBuffer = NULL; ++ + pDvdVideoPicture->pts = buffer->GetPts(); + if (!m_usePTS) + { + pDvdVideoPicture->pts = DVD_NOPTS_VALUE; + } +- buffer->Queue(m_frameInfo.pDisplayFrameBuf); +- pDvdVideoPicture->codecinfo = buffer; ++ ++ buffer->Queue(&m_frameInfo); + + #ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "+ %02d\n", idx); +- CLog::Log(LOGDEBUG, "pts %f\n",pDvdVideoPicture->pts); ++ CLog::Log(LOGDEBUG, "+ %02d pts %f (VPU)\n", idx, pDvdVideoPicture->pts); + #endif + ++ ipuBuffer = m_deinterlacer.Process(buffer, m_frameInfo.eFieldType, m_modeDeinterlace > 1); ++ ++ if (ipuBuffer) ++ pDvdVideoPicture->codecinfo = ipuBuffer; ++ else ++ pDvdVideoPicture->codecinfo = buffer; ++ + pDvdVideoPicture->codecinfo->Lock(); +- pDvdVideoPicture->codecinfo->iWidth = m_frameInfo.pExtInfo->nFrmWidth; +- pDvdVideoPicture->codecinfo->iHeight = m_frameInfo.pExtInfo->nFrmHeight; +- pDvdVideoPicture->codecinfo->data[0] = m_frameInfo.pDisplayFrameBuf->pbufVirtY; +- pDvdVideoPicture->codecinfo->data[1] = m_frameInfo.pDisplayFrameBuf->pbufY; + } + else + { +@@ -910,7 +945,7 @@ void CDVDVideoCodecIMXBuffer::Lock() + { + #ifdef TRACE_FRAMES + long count = AtomicIncrement(&m_refs); +- CLog::Log(LOGDEBUG, "R+ %02d - ref : %d\n", m_idx, count); ++ CLog::Log(LOGDEBUG, "R+ %02d - ref : %d (VPU)\n", m_idx, count); + #else + AtomicIncrement(&m_refs); + #endif +@@ -920,24 +955,22 @@ long CDVDVideoCodecIMXBuffer::Release() + { + long count = AtomicDecrement(&m_refs); + #ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "R- %02d - ref : %d\n", m_idx, count); ++ CLog::Log(LOGDEBUG, "R- %02d - ref : %d (VPU)\n", m_idx, count); + #endif + 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; + #ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "R %02d\n", m_idx); ++ CLog::Log(LOGDEBUG, "R %02d (VPU)\n", m_idx); + #endif ++ } + } + else if (count == 0) + { +-#ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "~ %02d\n", m_idx); +-#endif +- + delete this; + } + +@@ -950,16 +983,21 @@ bool CDVDVideoCodecIMXBuffer::IsValid() + return m_frameBuffer != NULL; + } + +-bool CDVDVideoCodecIMXBuffer::Rendered() ++bool CDVDVideoCodecIMXBuffer::Rendered() const + { + return m_rendered; + } + +-void CDVDVideoCodecIMXBuffer::Queue(VpuFrameBuffer *buffer) ++void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo) + { + CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); +- m_frameBuffer = buffer; ++ m_frameBuffer = frameInfo->pDisplayFrameBuf; + m_rendered = false; ++ ++ iWidth = frameInfo->pExtInfo->nFrmWidth; ++ iHeight = frameInfo->pExtInfo->nFrmHeight; ++ GET_VIRT_ADDR(this) = m_frameBuffer->pbufVirtY; ++ GET_PHYS_ADDR(this) = m_frameBuffer->pbufY; + } + + VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) +@@ -974,7 +1012,7 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + CLog::Log(LOGERROR, "%s: vpu clear frame display failure: ret=%d \r\n",__FUNCTION__,ret); + } + #ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "- %02d\n", m_idx); ++ CLog::Log(LOGDEBUG, "- %02d (VPU)\n", m_idx); + #endif + m_rendered = false; + m_frameBuffer = NULL; +@@ -995,4 +1033,363 @@ double CDVDVideoCodecIMXBuffer::GetPts(void) const + 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() ++{ ++ CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++ return (m_source != NULL) && m_pPhyAddr; ++} ++ ++bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffer, ++ CDVDVideoCodecBuffer *previousBuffer, VpuFieldType fieldType) ++{ ++ struct ipu_task task; ++ memset(&task, 0, sizeof(task)); ++ task.priority = IPU_TASK_PRIORITY_HIGH; ++ ++ SAFE_RELEASE(m_source); ++ ++ iWidth = currentBuffer->iWidth; ++ iHeight = currentBuffer->iHeight; ++ ++ // Input is the VPU decoded frame ++ task.input.width = iWidth; ++ task.input.height = iHeight; ++ task.input.format = IPU_PIX_FMT_NV12; ++ task.input.paddr = (int)GET_PHYS_ADDR(currentBuffer); ++ ++ // 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 previous buffer address ++ if (previousBuffer) ++ task.input.paddr_n = (int)GET_PHYS_ADDR(previousBuffer); ++ ++ task.input.deinterlace.enable = 1; ++ task.input.deinterlace.motion = task.input.paddr_n?LOW_MOTION:HIGH_MOTION; ++ ++ switch (fieldType) ++ { ++ case VPU_FIELD_TOP: ++ task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_TOP; ++ break; ++ case VPU_FIELD_BOTTOM: ++ task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM; ++ break; ++ /* ++ case VPU_FIELD_TB: ++ task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_TOP; ++ break; ++ case VPU_FIELD_BT: ++ task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM; ++ break; ++ */ ++ default: ++ break; ++ } ++ ++ int ret = ioctl(fd, IPU_QUEUE_TASK, &task); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "IPU task failed: %s\n", strerror(errno)); ++ return false; ++ } ++ ++ currentBuffer->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 = currentBuffer; ++ m_source->Lock(); ++ ++ currentBuffer->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) ++{ ++ uint8_t *phyAddr, *virtAddr; ++ 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; ++ } ++ ++ 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_lastBuffer(NULL) ++{ ++} ++ ++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]; ++ ++ 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() ++{ ++ SAFE_RELEASE(m_lastBuffer); ++ for (int i=0; i < m_bufferNum; i++) ++ m_buffers[i]->ReleaseFrameBuffer(); ++} ++ ++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; ++ SAFE_RELEASE(m_lastBuffer); ++ return true; ++} ++ ++CDVDVideoCodecIPUBuffer * ++CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer, ++ VpuFieldType fieldType, bool lowMotion) ++{ ++ CDVDVideoCodecIPUBuffer *target = NULL; ++ bool ret = true; ++ ++ 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] ++ CDVDVideoCodecBuffer *last = lowMotion?m_lastBuffer:NULL; ++ ret = m_buffers[i]->Process(m_ipuHandle, sourceBuffer, last, fieldType); ++ 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"); ++ } ++ ++ SAFE_RELEASE(m_lastBuffer); ++ m_lastBuffer = sourceBuffer; ++ if (m_lastBuffer != NULL) ++ m_lastBuffer->Lock(); ++ ++ return target; + } +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index d71e975..71a0d39 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -19,7 +19,6 @@ + * + */ + #include +-#include + #include + #include "DVDVideoCodec.h" + #include "DVDStreamInfo.h" +@@ -50,6 +49,8 @@ class CDecMemInfo + VpuMemDesc* phyMem; + }; + ++class CDVDVideoCodecIPUBuffer; ++ + class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + { + public: +@@ -60,32 +61,98 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + #endif + + // reference counting +- virtual void Lock(); +- virtual long Release(); +- virtual bool IsValid(); ++ virtual void Lock(); ++ virtual long Release(); ++ virtual bool IsValid(); + +- bool Rendered(); +- void Queue(VpuFrameBuffer *buffer); +- VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); +- void SetPts(double pts); +- double GetPts(void) const; ++ bool Rendered() const; ++ void Queue(VpuDecOutFrameInfo *frameInfo); ++ VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); ++ void SetPts(double pts); ++ double GetPts(void) const; + + protected: + // private because we are reference counted +- virtual ~CDVDVideoCodecIMXBuffer(); ++ virtual ~CDVDVideoCodecIMXBuffer(); ++ ++#ifdef TRACE_FRAMES ++ int m_idx; ++#endif ++ long m_refs; ++ VpuFrameBuffer *m_frameBuffer; ++ bool m_rendered; ++ double m_pts; ++}; ++ ++// 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, CDVDVideoCodecBuffer *currentBuffer, ++ CDVDVideoCodecBuffer *previousBuffer, VpuFieldType fieldType); ++ 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; ++ int m_idx; + #endif +- long m_refs; +- VpuFrameBuffer *m_frameBuffer; +- bool m_rendered; +- double m_pts; ++ 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; ++ CDVDVideoCodecBuffer *m_lastBuffer; ++}; ++ ++ + class CDVDVideoCodecIMX : public CDVDVideoCodec + { + friend class CDVDVideoCodecIMXBuffer; ++ friend class CDVDVideoCodecIPUBuffer; + + public: + CDVDVideoCodecIMX(); +@@ -104,10 +171,10 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + + protected: + +- bool VpuOpen(void); ++ bool VpuOpen(); + bool VpuAllocBuffers(VpuMemInfo *); +- bool VpuFreeBuffers(void); +- bool VpuAllocFrameBuffers(void); ++ bool VpuFreeBuffers(); ++ bool VpuAllocFrameBuffers(); + int VpuFindBuffer(void *frameAddr); + + static const int m_extraVpuBuffers; // Number of additional buffers for VPU +@@ -119,15 +186,16 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + 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_tsSyncRequired; // state whether timestamp manager has to be sync'ed + 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; + VpuMemDesc *m_extraMem; // Table of allocated extra Memory + // VpuMemDesc *m_outputBuffers; // Table of buffers out of VPU (used to call properly VPU_DecOutFrameDisplayed) + int m_frameCounter; // Decoded frames counter + bool m_usePTS; // State whether pts out of decoding process should be used ++ int m_modeDeinterlace; // Deinterlacer mode: 0=off, 1=high, 2..=low + VpuDecOutFrameInfo m_frameInfo; + CBitstreamConverter *m_converter; + bool m_convert_bitstream; +-- +1.9.3 + + +From d319a27f4d6a828efdc577b4f8747f3527df8e64 Mon Sep 17 00:00:00 2001 +From: tomlohave +Date: Sun, 2 Mar 2014 17:26:30 +0100 +Subject: [PATCH 34/56] fix CheckCompatibility for newer kernel (try2) + +Use "mxc_sdc_fb" instead of "mxc" as requested by Chris +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 65063e9..91e223f 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -46,7 +46,7 @@ CEGLNativeTypeIMX::~CEGLNativeTypeIMX() + bool CEGLNativeTypeIMX::CheckCompatibility() + { + std::string strName; +- std::string str2 ("mxc"); ++ std::string str2 ("mxc_sdc_fb"); + get_sysfs_str("/sys/class/graphics/fb0/device/modalias", strName); + StringUtils::Trim(strName); + size_t found = strName.find(str2); +-- +1.9.3 + + +From f6f6d7436f96c24ee8e291c049c25be0205435c7 Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Sun, 2 Mar 2014 03:05:46 +0100 +Subject: [PATCH 35/56] Properly track pts in case the associated frame is + consumed at next ::Decode call + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 40 +++++++++++++++++----- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 2 ++ + 2 files changed, 34 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 233e765..26ba552 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -364,6 +364,8 @@ CDVDVideoCodecIMX::CDVDVideoCodecIMX() + m_modeDeinterlace = atoi(deintEntry); + m_converter = NULL; + m_convert_bitstream = false; ++ m_bytesToBeConsumed = 0; ++ m_previousPts = DVD_NOPTS_VALUE; + } + + CDVDVideoCodecIMX::~CDVDVideoCodecIMX() +@@ -608,9 +610,10 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + ((unsigned int *)pData)[0] = htonl(iSize-4); + */ + +- if (pData && iSize) ++ if ((pData && iSize) || ++ (m_bytesToBeConsumed)) + { +- if (m_convert_bitstream) ++ if ((m_convert_bitstream) && (iSize)) + { + // convert demuxer packet from bitstream to bytestream (AnnexB) + if (m_converter->Convert(demuxer_content, demuxer_bytes)) +@@ -645,6 +648,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + #ifdef IMX_PROFILE + before_dec = XbmcThreads::SystemClockMillis(); + #endif ++ 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); +@@ -695,20 +699,24 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + 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 (pts != DVD_NOPTS_VALUE) ++ if (m_previousPts != DVD_NOPTS_VALUE) ++ { ++ m_outputBuffers[idx]->SetPts(m_previousPts); ++ m_previousPts = DVD_NOPTS_VALUE; ++ } ++ else + m_outputBuffers[idx]->SetPts(pts); +- else if (dts != DVD_NOPTS_VALUE) +- m_outputBuffers[idx]->SetPts(dts); + } + else +- { + CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); +- } + } + frameConsumed = true; + } //VPU_DEC_ONE_FRM_CONSUMED +@@ -804,7 +812,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + inData.nSize = 0; + retry = true; + } +- + } while (retry == true); + } //(pData && iSize) + +@@ -813,6 +820,21 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + 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; ++ if (retStatus & VC_PICTURE) ++ // If a picture was produced and some data are still to ++ // be consumed, do not ask for additional buffer as ++ // we likely already have enough data to produce a ++ // new output frame at next call ++ retStatus &= (~VC_BUFFER); ++ } ++ + #ifdef IMX_PROFILE + CLog::Log(LOGDEBUG, "%s - returns %x - duration %lld\n", __FUNCTION__, retStatus, XbmcThreads::SystemClockMillis() - previous); + #endif +@@ -834,6 +856,8 @@ void CDVDVideoCodecIMX::Reset() + + m_frameCounter = 0; + m_deinterlacer.Reset(); ++ m_bytesToBeConsumed = 0; ++ m_previousPts = DVD_NOPTS_VALUE; + + // Flush VPU + ret = VPU_DecFlushAll(m_vpuHandle); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 71a0d39..1cfb2a4 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -199,4 +199,6 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + 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 + }; +-- +1.9.3 + + +From d903f7bcffdff65493c29d3a9b52ed50042f8489 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Fri, 28 Feb 2014 12:48:26 +0100 +Subject: [PATCH 36/56] [imx] attempt to recover audio from resolution change + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 91e223f..4ffa708 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -32,6 +32,7 @@ + #include "utils/Environment.h" + #include "guilib/gui3d.h" + #include "windowing/WindowingFactory.h" ++#include "cores/AudioEngine/AEFactory.h" + + CEGLNativeTypeIMX::CEGLNativeTypeIMX() + : m_display(NULL) +@@ -201,6 +202,10 @@ bool CEGLNativeTypeIMX::SetNativeResolution(const RESOLUTION_INFO &res) + CreateNativeDisplay(); + + CLog::Log(LOGDEBUG, "%s: %s",__FUNCTION__, res.strId.c_str()); ++ ++ // Reset AE ++ CAEFactory::DeviceChange(); ++ + return true; + } + +-- +1.9.3 + + +From 6ab8235cd5a99eb9354c4c4e36ce00e610732bb7 Mon Sep 17 00:00:00 2001 +From: "Chris \"koying\" Browet" +Date: Fri, 28 Feb 2014 19:12:16 +0000 +Subject: [PATCH 37/56] [imx] A VPU_DEC_FLUSH should amount to a Reset() + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 26ba552..44bfe34 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -781,11 +781,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + if (decRet & VPU_DEC_FLUSH) + { + CLog::Log(LOGNOTICE, "%s - VPU requires a flush.\n", __FUNCTION__); +- ret = VPU_DecFlushAll(m_vpuHandle); +- if (ret != VPU_DEC_RET_SUCCESS) +- { +- CLog::Log(LOGERROR, "%s - VPU flush failed(%d).\n", __FUNCTION__, ret); +- } ++ Reset(); + retStatus = VC_FLUSHED; + } + if (decRet & VPU_DEC_OUTPUT_EOS) +-- +1.9.3 + + +From 91ecb933bc80e9e2e809b147253ac114ac00c8d8 Mon Sep 17 00:00:00 2001 +From: "Chris \"Koying\" Browet" +Date: Tue, 4 Mar 2014 12:48:32 +0100 +Subject: [PATCH 38/56] CHG: [imx] decouple compile options for vpu & fb + +--- + configure.in | 9 +++++++++ + xbmc/windowing/egl/EGLWrapper.cpp | 2 +- + xbmc/windowing/egl/Makefile.in | 2 +- + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/configure.in b/configure.in +index abc9d01..0a5e902 100644 +--- a/configure.in ++++ b/configure.in +@@ -978,6 +978,15 @@ else + 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" +diff --git a/xbmc/windowing/egl/EGLWrapper.cpp b/xbmc/windowing/egl/EGLWrapper.cpp +index 717b369..4d74be5 100644 +--- a/xbmc/windowing/egl/EGLWrapper.cpp ++++ b/xbmc/windowing/egl/EGLWrapper.cpp +@@ -85,7 +85,7 @@ bool CEGLWrapper::Initialize(const std::string &implementation) + (nativeGuess = CreateEGLNativeType(implementation)) || + (nativeGuess = CreateEGLNativeType(implementation)) || + (nativeGuess = CreateEGLNativeType(implementation)) +-#ifdef HAS_IMXVPU ++#ifdef HAS_IMXFB + || (nativeGuess = CreateEGLNativeType(implementation)) + #endif + ) +diff --git a/xbmc/windowing/egl/Makefile.in b/xbmc/windowing/egl/Makefile.in +index 85abb44..ec84c1d 100644 +--- a/xbmc/windowing/egl/Makefile.in ++++ b/xbmc/windowing/egl/Makefile.in +@@ -24,7 +24,7 @@ SRCS+= wayland/Callback.cpp \ + wayland/XBMCSurface.cpp + endif + +-ifeq (@USE_IMXVPU@,1) ++ifeq (@USE_IMXFB@,1) + SRCS+= EGLNativeTypeIMX.cpp + endif + +-- +1.9.3 + + +From 10c22eb22a1684622350520c68092a4e378fb453 Mon Sep 17 00:00:00 2001 +From: "Chris \"koying\" Browet" +Date: Mon, 3 Mar 2014 18:46:45 +0000 +Subject: [PATCH 39/56] FIX: [imx] lower log spam + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 44bfe34..a6f3712 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -941,7 +941,9 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) + if (m_dropState != bDrop) + { + m_dropState = bDrop; +- CLog::Log(LOGNOTICE, "%s : %d\n", __FUNCTION__, bDrop); ++#ifdef TRACE_FRAMES ++ CLog::Log(LOGDEBUG, "%s : %d\n", __FUNCTION__, bDrop); ++#endif + } + } + +-- +1.9.3 + + +From 9064e76224bf94b67bc46508db23bcb30b6f8894 Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Sat, 15 Mar 2014 02:30:15 +0100 +Subject: [PATCH 40/56] Revert to sw decoding for AVC hi10 profile and divX3 + codecs + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index a6f3712..4110f83 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -422,6 +422,11 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + 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) +@@ -463,10 +468,6 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + m_decOpenParam.CodecFormat = VPU_V_VP8; + m_pFormatName = "iMX-vp8"; + break; +- case CODEC_ID_MSMPEG4V3: +- m_decOpenParam.CodecFormat = VPU_V_XVID; // VPU_V_DIVX3 +- m_pFormatName = "iMX-divx3"; +- break; + case CODEC_ID_MPEG4: + switch(m_hints.codec_tag) + { +-- +1.9.3 + + +From 260df66f3fac6965578e42b28d972445c6d16f13 Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Sun, 16 Mar 2014 01:53:02 +0100 +Subject: [PATCH 41/56] Add VPU support for MPEG1 + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 4110f83..a4f6ede 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -412,6 +412,10 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + 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; +-- +1.9.3 + + +From 2266cf79a1eeff8828c9e68dc1e23c2a7410f15a Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Sun, 16 Mar 2014 23:53:01 +0100 +Subject: [PATCH 42/56] Avoid to invoke VPU decoding without additional data + when we are not specifically in PR28 context as it improves VC1 issue + reported in #41 To do so, Test if frame size (and thus + VPU_DEC_ONE_FRM_CONSUMED) is handled before dealing with m_bytesToBeConsumed + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 15 ++++++++++++++- + xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 1 + + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index a4f6ede..9c23de2 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -211,6 +211,18 @@ bool CDVDVideoCodecIMX::VpuOpen(void) + 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: +@@ -653,7 +665,8 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + #ifdef IMX_PROFILE + before_dec = XbmcThreads::SystemClockMillis(); + #endif +- m_bytesToBeConsumed += inData.nSize; ++ 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); +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 1cfb2a4..6c935f1 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -201,4 +201,5 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + 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 + }; +-- +1.9.3 + + +From f6b11849813afabef4d3c4b4e1f7e01085a7233c Mon Sep 17 00:00:00 2001 +From: wolfgar +Date: Wed, 19 Mar 2014 03:08:48 +0100 +Subject: [PATCH 43/56] Handle dts properly instead of reverting to NOPTS when + only dts is available (no pts provided) Also try to decode harder + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 56 ++++++++++------------ + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 2 + + 2 files changed, 26 insertions(+), 32 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 9c23de2..ffbfd59 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -46,6 +46,7 @@ + + // 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) +@@ -413,7 +414,7 @@ bool CDVDVideoCodecIMX::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) + { + char buf[4096]; + +- for (int i=0; i < m_hints.extrasize; i++) ++ 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); + } +@@ -588,8 +589,7 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + int retStatus = 0; + int demuxer_bytes = iSize; + uint8_t *demuxer_content = pData; +- bool retry = false; +- bool frameConsumed = false; ++ int retries = 0; + int idx; + + #ifdef IMX_PROFILE +@@ -622,11 +622,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + previous = current; + #endif + +-/* FIXME tests +- CLog::Log(LOGDEBUG, "%s - demux size : %d dts : %f - pts : %f - %x %x %x %x\n", __FUNCTION__, iSize, dts, pts, ((unsigned int *)pData)[0], ((unsigned int *)pData)[1], ((unsigned int *)pData)[2], ((unsigned int *)pData)[3]); +- ((unsigned int *)pData)[0] = htonl(iSize-4); +-*/ +- + if ((pData && iSize) || + (m_bytesToBeConsumed)) + { +@@ -659,9 +654,8 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + inData.sCodecData.nSize = 0; + } + +- do // Decode as long as the VPU consumes data ++ while (true) // Decode as long as the VPU consumes data + { +- retry = false; + #ifdef IMX_PROFILE + before_dec = XbmcThreads::SystemClockMillis(); + #endif +@@ -736,7 +730,6 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + else + CLog::Log(LOGERROR, "%s - could not find frame buffer\n", __FUNCTION__); + } +- frameConsumed = true; + } //VPU_DEC_ONE_FRM_CONSUMED + + if (decRet & VPU_DEC_OUTPUT_DIS) +@@ -806,27 +799,30 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + { + CLog::Log(LOGNOTICE, "%s - EOS encountered.\n", __FUNCTION__); + } +- if (decRet & VPU_DEC_NO_ENOUGH_INBUF) ++ if ((decRet & VPU_DEC_NO_ENOUGH_INBUF) || ++ (decRet & VPU_DEC_OUTPUT_DIS)) + { + // We are done with VPU decoder that time + break; + } +- if (!(decRet & VPU_DEC_INPUT_USED)) ++ ++ retries++; ++ if (retries >= m_maxVpuDecodeLoops) + { +- CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize); ++ CLog::Log(LOGERROR, "%s - Leaving VPU decoding loop after %d iterations\n", __FUNCTION__, m_maxVpuDecodeLoops); ++ break; + } + +- if (!(decRet & VPU_DEC_OUTPUT_DIS) && +- (inData.nSize != 0)) ++ if (!(decRet & VPU_DEC_INPUT_USED)) + { +- // 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; +- retry = true; ++ CLog::Log(LOGERROR, "%s - input not used : addr %p size :%d!\n", __FUNCTION__, inData.pVirAddr, inData.nSize); + } +- } while (retry == true); ++ ++ // 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) +@@ -841,13 +837,9 @@ int CDVDVideoCodecIMX::Decode(BYTE *pData, int iSize, double dts, double pts) + // This pts is related to the frame that will be consumed + // at next call... + m_previousPts = pts; +- if (retStatus & VC_PICTURE) +- // If a picture was produced and some data are still to +- // be consumed, do not ask for additional buffer as +- // we likely already have enough data to produce a +- // new output frame at next call +- retStatus &= (~VC_BUFFER); + } ++ // 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); +@@ -921,17 +913,18 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + CDVDVideoCodecIPUBuffer *ipuBuffer = NULL; + + 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); + + #ifdef TRACE_FRAMES +- CLog::Log(LOGDEBUG, "+ %02d pts %f (VPU)\n", idx, pDvdVideoPicture->pts); ++ CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); + #endif +- + ipuBuffer = m_deinterlacer.Process(buffer, m_frameInfo.eFieldType, m_modeDeinterlace > 1); + + if (ipuBuffer) +@@ -1219,7 +1212,6 @@ void CDVDVideoCodecIPUBuffer::ReleaseFrameBuffer() + + bool CDVDVideoCodecIPUBuffer::Allocate(int fd, int width, int height, int nAlign) + { +- uint8_t *phyAddr, *virtAddr; + m_iWidth = Align(width,FRAME_ALIGN); + m_iHeight = Align(height,(2*FRAME_ALIGN)); + // NV12 == 12 bpp +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 6c935f1..1ae2618 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -178,6 +178,7 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + 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 +@@ -202,4 +203,5 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + int m_bytesToBeConsumed; // Remaining bytes in VPU + double m_previousPts; // Enable to keep pts when needed + bool m_frameReported; // State whether the frame consumed event will be reported by libfslvpu ++ double m_dts; // Current dts + }; +-- +1.9.3 + + +From 2ff1d520759e2fc0f7992534c24dda1e2cf2de5f Mon Sep 17 00:00:00 2001 +From: smallint +Date: Sun, 2 Mar 2014 17:13:52 +0100 +Subject: [PATCH 44/56] [imx] Move deinterlacing processing into render thread + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 40 ++++++++- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 95 ++++++++++++++-------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 6 ++ + 3 files changed, 103 insertions(+), 38 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 980c1a3..8b0f555 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -81,6 +81,8 @@ static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; + + #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); +@@ -1640,7 +1642,15 @@ void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) + YUVPLANE &plane = m_buffers[index].fields[field][0]; + CDVDVideoCodecBuffer* codecinfo = m_buffers[index].codecinfo; + +- if((codecinfo == NULL) || !codecinfo->IsValid()) return; ++ if(codecinfo == NULL) return; ++ ++ CDVDVideoCodecIMX::Enter(); ++ ++ if(!codecinfo->IsValid()) ++ { ++ CDVDVideoCodecIMX::Leave(); ++ return; ++ } + + glDisable(GL_DEPTH_TEST); + +@@ -1693,6 +1703,8 @@ void CLinuxRendererGLES::RenderIMXMAPTexture(int index, int field) + glBindTexture(m_textureTarget, 0); + VerifyGLState(); + ++ CDVDVideoCodecIMX::Leave(); ++ + #ifdef DEBUG_VERBOSE + CLog::Log(LOGDEBUG, "RenderIMXMAPTexture %d: tm:%d\n", index, XbmcThreads::SystemClockMillis() - time); + #endif +@@ -2716,9 +2728,31 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + YUVBUFFER& buf = m_buffers[index]; + CDVDVideoCodecBuffer* codecinfo = buf.codecinfo; + +- if(codecinfo && codecinfo->IsValid()) ++ 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) ++ { ++ CDVDVideoCodecBuffer *deint; ++ deint = deinterlacer->Process(codecinfo, (VpuFieldType)(int)codecinfo->data[3], false); ++ if (deint) ++ { ++ SAFE_RELEASE(buf.codecinfo); ++ buf.codecinfo = deint; ++ buf.codecinfo->Lock(); ++ codecinfo = buf.codecinfo; ++ } ++ } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(m_textureTarget, plane.id); +@@ -2736,6 +2770,8 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + plane.texheight = codecinfo->iHeight; + + CalculateTextureSourceRects(index, 1); ++ ++ CDVDVideoCodecIMX::Leave(); + } + + #endif +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index ffbfd59..752bfb9 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -43,6 +43,8 @@ + // 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; +@@ -334,20 +336,12 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + + if (m_initInfo.nInterlace && (m_modeDeinterlace>0)) + { +- if ((m_initInfo.nPicWidth>1024) || (m_initInfo.nPicHeight>1024)) ++ CLog::Log(LOGNOTICE, "IMX: Enable hardware deinterlacing\n"); ++ if (!m_deinterlacer.Init(m_initInfo.nPicWidth, m_initInfo.nPicHeight, GetAllowedReferences()+1, nAlign)) + { +- CLog::Log(LOGNOTICE, "IMX: Disable hardware deinterlacing for HD playback\n"); ++ CLog::Log(LOGWARNING, "IMX: Failed to initialize IPU buffers: deinterlacing disabled\n"); + m_modeDeinterlace = 0; + } +- else +- { +- 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"); +- m_modeDeinterlace = 0; +- } +- } + } + else + m_modeDeinterlace = 0; +@@ -522,6 +516,9 @@ void CDVDVideoCodecIMX::Dispose(void) + VpuDecRetCode ret; + bool VPU_loaded = m_vpuHandle; + ++ // Block render thread from using that framebuffers ++ Enter(); ++ + // Invalidate output buffers to prevent the renderer from mapping this memory + for (int i=0; iiFlags = DVP_FLAG_ALLOCATED; + if (m_dropState) + pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED; +@@ -910,7 +910,6 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + if (idx != -1) + { + CDVDVideoCodecIMXBuffer *buffer = m_outputBuffers[idx]; +- CDVDVideoCodecIPUBuffer *ipuBuffer = NULL; + + pDvdVideoPicture->pts = buffer->GetPts(); + pDvdVideoPicture->dts = m_dts; +@@ -925,13 +924,10 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); + #endif +- ipuBuffer = m_deinterlacer.Process(buffer, m_frameInfo.eFieldType, m_modeDeinterlace > 1); + +- if (ipuBuffer) +- pDvdVideoPicture->codecinfo = ipuBuffer; +- else +- pDvdVideoPicture->codecinfo = buffer; ++ GET_DEINTERLACER(buffer) = (uint8_t*)&m_deinterlacer; + ++ pDvdVideoPicture->codecinfo = buffer; + pDvdVideoPicture->codecinfo->Lock(); + } + else +@@ -958,6 +954,16 @@ void CDVDVideoCodecIMX::SetDropState(bool bDrop) + } + } + ++void CDVDVideoCodecIMX::Enter() ++{ ++ m_codecBufferLock.lock(); ++} ++ ++void CDVDVideoCodecIMX::Leave() ++{ ++ m_codecBufferLock.unlock(); ++} ++ + /*******************************************/ + + #ifdef TRACE_FRAMES +@@ -1012,7 +1018,6 @@ long CDVDVideoCodecIMXBuffer::Release() + + bool CDVDVideoCodecIMXBuffer::IsValid() + { +- CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); + return m_frameBuffer != NULL; + } + +@@ -1023,7 +1028,8 @@ bool CDVDVideoCodecIMXBuffer::Rendered() const + + void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo) + { +- CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++ // No lock necessary because at the time Queue there is definitely no ++ // thread that is still holding a reference + m_frameBuffer = frameInfo->pDisplayFrameBuf; + m_rendered = false; + +@@ -1031,11 +1037,13 @@ void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo) + 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) + { +- CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); ++ // 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) +@@ -1047,6 +1055,7 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "- %02d (VPU)\n", m_idx); + #endif ++ GET_DEINTERLACER(this) = NULL; + m_rendered = false; + m_frameBuffer = NULL; + m_pts = DVD_NOPTS_VALUE; +@@ -1125,8 +1134,7 @@ long CDVDVideoCodecIPUBuffer::Release() + + bool CDVDVideoCodecIPUBuffer::IsValid() + { +- CSingleLock lock(CDVDVideoCodecIMX::m_codecBufferLock); +- return (m_source != NULL) && m_pPhyAddr; ++ return m_source && m_source->IsValid() && m_pPhyAddr; + } + + bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffer, +@@ -1138,27 +1146,27 @@ bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffe + + SAFE_RELEASE(m_source); + +- iWidth = currentBuffer->iWidth; +- iHeight = currentBuffer->iHeight; ++ iWidth = currentBuffer->iWidth; ++ iHeight = currentBuffer->iHeight; + + // Input is the VPU decoded frame +- task.input.width = iWidth; +- task.input.height = iHeight; +- task.input.format = IPU_PIX_FMT_NV12; +- task.input.paddr = (int)GET_PHYS_ADDR(currentBuffer); ++ task.input.width = iWidth; ++ task.input.height = iHeight; ++ task.input.format = IPU_PIX_FMT_NV12; ++ task.input.paddr = (int)GET_PHYS_ADDR(currentBuffer); + + // 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); ++ task.output.width = iWidth; ++ task.output.height = iHeight; ++ task.output.format = IPU_PIX_FMT_NV12; ++ task.output.paddr = (int)GET_PHYS_ADDR(this); + + // Fill previous buffer address + if (previousBuffer) + task.input.paddr_n = (int)GET_PHYS_ADDR(previousBuffer); + +- task.input.deinterlace.enable = 1; +- task.input.deinterlace.motion = task.input.paddr_n?LOW_MOTION:HIGH_MOTION; ++ task.input.deinterlace.enable = 1; ++ task.input.deinterlace.motion = task.input.paddr_n?LOW_MOTION:HIGH_MOTION; + + switch (fieldType) + { +@@ -1180,7 +1188,13 @@ bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffe + 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)); +@@ -1250,6 +1264,8 @@ bool CDVDVideoCodecIPUBuffer::Allocate(int fd, int width, int height, int nAlign + GET_VIRT_ADDR(this) = (uint8_t*)m_pVirtAddr; + } + ++ GET_DEINTERLACER(this) = NULL; ++ + return true; + } + +@@ -1290,7 +1306,8 @@ bool CDVDVideoCodecIPUBuffer::Free(int fd) + } + + CDVDVideoCodecIPUBuffers::CDVDVideoCodecIPUBuffers() +- : m_ipuHandle(0) ++ : m_bEnabled(true) ++ , m_ipuHandle(0) + , m_bufferNum(0) + , m_buffers(NULL) + , m_lastBuffer(NULL) +@@ -1346,6 +1363,11 @@ bool CDVDVideoCodecIPUBuffers::Reset() + m_buffers[i]->ReleaseFrameBuffer(); + } + ++bool CDVDVideoCodecIPUBuffers::SetEnabled(bool enabled) ++{ ++ m_bEnabled = enabled; ++} ++ + bool CDVDVideoCodecIPUBuffers::Close() + { + bool ret = true; +@@ -1390,7 +1412,8 @@ CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer, + CDVDVideoCodecIPUBuffer *target = NULL; + bool ret = true; + +- if (!m_bufferNum || (fieldType==VPU_FIELD_NONE)) return NULL; ++ if (!m_bEnabled || !m_bufferNum) ++ return NULL; + + for (int i=0; i < m_bufferNum; i++ ) + { +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 1ae2618..1b1786e 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -75,6 +75,7 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + // private because we are reference counted + virtual ~CDVDVideoCodecIMXBuffer(); + ++private: + #ifdef TRACE_FRAMES + int m_idx; + #endif +@@ -136,12 +137,14 @@ class CDVDVideoCodecIPUBuffers + + bool Init(int width, int height, int numBuffers, int nAlign); + bool Reset(); ++ bool SetEnabled(bool); + bool Close(); + + CDVDVideoCodecIPUBuffer *Process(CDVDVideoCodecBuffer *sourceBuffer, + VpuFieldType fieldType, bool lowMotion); + + private: ++ bool m_bEnabled; + int m_ipuHandle; + int m_bufferNum; + CDVDVideoCodecIPUBuffer **m_buffers; +@@ -169,6 +172,9 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + virtual const char* GetName(void) { return (const char*)m_pFormatName; } + virtual unsigned GetAllowedReferences(); + ++ static void Enter(); ++ static void Leave(); ++ + protected: + + bool VpuOpen(); +-- +1.9.3 + + +From e63bd0444c55a992febca76b34f84eaa227c2c83 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Mon, 3 Mar 2014 19:39:17 +0100 +Subject: [PATCH 45/56] ADD: [imx] Deinterlacing options configurable from gui + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 38 +++++++++++++++++----- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 15 +++++++-- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 2 +- + 3 files changed, 42 insertions(+), 13 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 8b0f555..8a28e3b 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -2725,7 +2725,7 @@ void CLinuxRendererGLES::SetTextureFilter(GLenum method) + void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + { + #ifdef HAS_IMXVPU +- YUVBUFFER& buf = m_buffers[index]; ++ YUVBUFFER& buf = m_buffers[index]; + CDVDVideoCodecBuffer* codecinfo = buf.codecinfo; + + if(codecinfo) +@@ -2740,18 +2740,27 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + + YUVPLANE &plane = m_buffers[index].fields[0][0]; + CDVDVideoCodecIPUBuffers *deinterlacer = (CDVDVideoCodecIPUBuffers*)codecinfo->data[2]; ++ EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++ EINTERLACEMETHOD interlacemethod = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; + + if (deinterlacer) + { +- CDVDVideoCodecBuffer *deint; +- deint = deinterlacer->Process(codecinfo, (VpuFieldType)(int)codecinfo->data[3], false); +- if (deint) ++ if (deinterlacemode != VS_DEINTERLACEMODE_OFF) + { +- SAFE_RELEASE(buf.codecinfo); +- buf.codecinfo = deint; +- buf.codecinfo->Lock(); +- codecinfo = buf.codecinfo; ++ deinterlacer->SetEnabled(true); ++ CDVDVideoCodecBuffer *deint; ++ 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; ++ } + } ++ else ++ deinterlacer->SetEnabled(false); + } + + glActiveTexture(GL_TEXTURE0); +@@ -2886,9 +2895,14 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode) + 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; + } +@@ -2917,6 +2931,7 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) + if(method == VS_INTERLACEMETHOD_AUTO) + return true; + ++#ifndef HAS_IMXVPU + #if defined(__i386__) || defined(__x86_64__) + if(method == VS_INTERLACEMETHOD_DEINTERLACE + || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF +@@ -2925,6 +2940,11 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) + if(method == VS_INTERLACEMETHOD_SW_BLEND) + #endif + return true; ++#else ++ if(method == VS_INTERLACEMETHOD_DEINTERLACE ++ || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF) ++ return true; ++#endif + + return false; + } +@@ -2965,7 +2985,7 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() + if(m_renderMethod & RENDER_CVREF) + return VS_INTERLACEMETHOD_NONE; + +-#if defined(__i386__) || defined(__x86_64__) ++#if defined(__i386__) || defined(__x86_64__) || defined(HAS_IMXVPU) + return VS_INTERLACEMETHOD_DEINTERLACE_HALF; + #else + return VS_INTERLACEMETHOD_SW_BLEND; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 752bfb9..11d06d7 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -890,6 +890,15 @@ bool CDVDVideoCodecIMX::ClearPicture(DVDVideoPicture* pDvdVideoPicture) + + 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; +@@ -1028,8 +1037,8 @@ bool CDVDVideoCodecIMXBuffer::Rendered() const + + void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo) + { +- // No lock necessary because at the time Queue there is definitely no +- // thread that is still holding a reference ++ // No lock necessary because at this time there is definitely no ++ // thread still holding a reference + m_frameBuffer = frameInfo->pDisplayFrameBuf; + m_rendered = false; + +@@ -1363,7 +1372,7 @@ bool CDVDVideoCodecIPUBuffers::Reset() + m_buffers[i]->ReleaseFrameBuffer(); + } + +-bool CDVDVideoCodecIPUBuffers::SetEnabled(bool enabled) ++void CDVDVideoCodecIPUBuffers::SetEnabled(bool enabled) + { + m_bEnabled = enabled; + } +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 1b1786e..37d5734 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -137,7 +137,7 @@ class CDVDVideoCodecIPUBuffers + + bool Init(int width, int height, int numBuffers, int nAlign); + bool Reset(); +- bool SetEnabled(bool); ++ void SetEnabled(bool); + bool Close(); + + CDVDVideoCodecIPUBuffer *Process(CDVDVideoCodecBuffer *sourceBuffer, +-- +1.9.3 + + +From 63c66af9fb1e0a23fdbcec838e0559d0da89cd6f Mon Sep 17 00:00:00 2001 +From: smallint +Date: Tue, 11 Mar 2014 20:49:40 +0100 +Subject: [PATCH 46/56] [imx] Cleanups after code review + +--- + xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 28 ++++++++++++---------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 21 +++++++--------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 2 -- + 3 files changed, 25 insertions(+), 26 deletions(-) + +diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +index 8a28e3b..6490fd0f 100644 +--- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ++++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp +@@ -2740,15 +2740,15 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + + YUVPLANE &plane = m_buffers[index].fields[0][0]; + CDVDVideoCodecIPUBuffers *deinterlacer = (CDVDVideoCodecIPUBuffers*)codecinfo->data[2]; +- EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; +- EINTERLACEMETHOD interlacemethod = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; + + if (deinterlacer) + { ++ EDEINTERLACEMODE deinterlacemode = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode; ++ + if (deinterlacemode != VS_DEINTERLACEMODE_OFF) + { +- deinterlacer->SetEnabled(true); + CDVDVideoCodecBuffer *deint; ++ EINTERLACEMETHOD interlacemethod = CMediaSettings::Get().GetCurrentVideoSettings().m_InterlaceMethod; + deint = deinterlacer->Process(codecinfo, (VpuFieldType)(int)codecinfo->data[3], + interlacemethod == VS_INTERLACEMETHOD_DEINTERLACE); + if (deint) +@@ -2759,8 +2759,6 @@ void CLinuxRendererGLES::UploadIMXMAPTexture(int index) + codecinfo = buf.codecinfo; + } + } +- else +- deinterlacer->SetEnabled(false); + } + + glActiveTexture(GL_TEXTURE0); +@@ -2931,7 +2929,15 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) + if(method == VS_INTERLACEMETHOD_AUTO) + return true; + +-#ifndef HAS_IMXVPU ++ 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 +@@ -2940,11 +2946,6 @@ bool CLinuxRendererGLES::Supports(EINTERLACEMETHOD method) + if(method == VS_INTERLACEMETHOD_SW_BLEND) + #endif + return true; +-#else +- if(method == VS_INTERLACEMETHOD_DEINTERLACE +- || method == VS_INTERLACEMETHOD_DEINTERLACE_HALF) +- return true; +-#endif + + return false; + } +@@ -2985,7 +2986,10 @@ EINTERLACEMETHOD CLinuxRendererGLES::AutoInterlaceMethod() + if(m_renderMethod & RENDER_CVREF) + return VS_INTERLACEMETHOD_NONE; + +-#if defined(__i386__) || defined(__x86_64__) || defined(HAS_IMXVPU) ++ if(m_renderMethod & RENDER_IMXMAP) ++ return VS_INTERLACEMETHOD_DEINTERLACE_HALF; ++ ++#if defined(__i386__) || defined(__x86_64__) + return VS_INTERLACEMETHOD_DEINTERLACE_HALF; + #else + return VS_INTERLACEMETHOD_SW_BLEND; +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 11d06d7..4dc3169 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -342,6 +342,11 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + CLog::Log(LOGWARNING, "IMX: Failed to initialize IPU buffers: deinterlacing disabled\n"); + m_modeDeinterlace = 0; + } ++ else ++ { ++ for (int i=0 ; i < m_vpuFrameBufferNum; i++) ++ GET_DEINTERLACER(m_outputBuffers[i]) = (uint8_t*)&m_deinterlacer; ++ } + } + else + m_modeDeinterlace = 0; +@@ -934,8 +939,6 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + CLog::Log(LOGDEBUG, "+ %02d dts %f pts %f (VPU)\n", idx, pDvdVideoPicture->dts, pDvdVideoPicture->pts); + #endif + +- GET_DEINTERLACER(buffer) = (uint8_t*)&m_deinterlacer; +- + pDvdVideoPicture->codecinfo = buffer; + pDvdVideoPicture->codecinfo->Lock(); + } +@@ -987,6 +990,7 @@ CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() + , m_rendered(false) + , m_pts(DVD_NOPTS_VALUE) + { ++ GET_DEINTERLACER(this) = NULL; + } + + void CDVDVideoCodecIMXBuffer::Lock() +@@ -1064,7 +1068,6 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "- %02d (VPU)\n", m_idx); + #endif +- GET_DEINTERLACER(this) = NULL; + m_rendered = false; + m_frameBuffer = NULL; + m_pts = DVD_NOPTS_VALUE; +@@ -1315,8 +1318,7 @@ bool CDVDVideoCodecIPUBuffer::Free(int fd) + } + + CDVDVideoCodecIPUBuffers::CDVDVideoCodecIPUBuffers() +- : m_bEnabled(true) +- , m_ipuHandle(0) ++ : m_ipuHandle(0) + , m_bufferNum(0) + , m_buffers(NULL) + , m_lastBuffer(NULL) +@@ -1348,7 +1350,7 @@ bool CDVDVideoCodecIPUBuffers::Init(int width, int height, int numBuffers, int n + m_bufferNum = numBuffers; + m_buffers = new CDVDVideoCodecIPUBuffer*[m_bufferNum]; + +- for (int i=0; i < m_bufferNum; i++ ) ++ for (int i=0; i < m_bufferNum; i++) + { + #ifdef TRACE_FRAMES + m_buffers[i] = new CDVDVideoCodecIPUBuffer(i); +@@ -1372,11 +1374,6 @@ bool CDVDVideoCodecIPUBuffers::Reset() + m_buffers[i]->ReleaseFrameBuffer(); + } + +-void CDVDVideoCodecIPUBuffers::SetEnabled(bool enabled) +-{ +- m_bEnabled = enabled; +-} +- + bool CDVDVideoCodecIPUBuffers::Close() + { + bool ret = true; +@@ -1421,7 +1418,7 @@ CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer, + CDVDVideoCodecIPUBuffer *target = NULL; + bool ret = true; + +- if (!m_bEnabled || !m_bufferNum) ++ if (!m_bufferNum) + return NULL; + + for (int i=0; i < m_bufferNum; i++ ) +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index 37d5734..a76575f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -137,14 +137,12 @@ class CDVDVideoCodecIPUBuffers + + bool Init(int width, int height, int numBuffers, int nAlign); + bool Reset(); +- void SetEnabled(bool); + bool Close(); + + CDVDVideoCodecIPUBuffer *Process(CDVDVideoCodecBuffer *sourceBuffer, + VpuFieldType fieldType, bool lowMotion); + + private: +- bool m_bEnabled; + int m_ipuHandle; + int m_bufferNum; + CDVDVideoCodecIPUBuffer **m_buffers; +-- +1.9.3 + + +From 36f7165a1b80a47531b9f5757a6fae4bbce754c2 Mon Sep 17 00:00:00 2001 +From: smallint +Date: Fri, 14 Mar 2014 15:27:24 +0000 +Subject: [PATCH 47/56] [imx] Fixed low motion deinterlacing picture jumps + +--- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp | 129 ++++++++++++++------- + .../dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h | 64 +++++----- + 2 files changed, 121 insertions(+), 72 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +index 4dc3169..782510f 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp +@@ -334,22 +334,19 @@ bool CDVDVideoCodecIMX::VpuAllocFrameBuffers(void) + #endif + } + +- if (m_initInfo.nInterlace && (m_modeDeinterlace>0)) ++ 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"); +- m_modeDeinterlace = 0; + } + else + { +- for (int i=0 ; i < m_vpuFrameBufferNum; i++) ++ for (int i=0; iReleaseFramebuffer(&m_vpuHandle); +@@ -933,14 +935,30 @@ bool CDVDVideoCodecIMX::GetPicture(DVDVideoPicture* pDvdVideoPicture) + pDvdVideoPicture->dts = DVD_NOPTS_VALUE; + } + +- buffer->Queue(&m_frameInfo); ++ 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 + { +@@ -989,6 +1007,7 @@ CDVDVideoCodecIMXBuffer::CDVDVideoCodecIMXBuffer() + , m_frameBuffer(NULL) + , m_rendered(false) + , m_pts(DVD_NOPTS_VALUE) ++ , m_previousBuffer(NULL) + { + GET_DEINTERLACER(this) = NULL; + } +@@ -1009,6 +1028,11 @@ long CDVDVideoCodecIMXBuffer::Release() + #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 +@@ -1016,6 +1040,7 @@ long CDVDVideoCodecIMXBuffer::Release() + if(m_frameBuffer != NULL) + { + m_rendered = true; ++ SAFE_RELEASE(m_previousBuffer); + #ifdef TRACE_FRAMES + CLog::Log(LOGDEBUG, "R %02d (VPU)\n", m_idx); + #endif +@@ -1039,12 +1064,16 @@ bool CDVDVideoCodecIMXBuffer::Rendered() const + return m_rendered; + } + +-void CDVDVideoCodecIMXBuffer::Queue(VpuDecOutFrameInfo *frameInfo) ++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; +@@ -1071,6 +1100,8 @@ VpuDecRetCode CDVDVideoCodecIMXBuffer::ReleaseFramebuffer(VpuDecHandle *handle) + m_rendered = false; + m_frameBuffer = NULL; + m_pts = DVD_NOPTS_VALUE; ++ SAFE_RELEASE(m_previousBuffer); ++ + return ret; + } + +@@ -1084,6 +1115,11 @@ double CDVDVideoCodecIMXBuffer::GetPts(void) const + return m_pts; + } + ++CDVDVideoCodecIMXBuffer *CDVDVideoCodecIMXBuffer::GetPreviousBuffer() const ++{ ++ return m_previousBuffer; ++} ++ + CDVDVideoCodecIMXBuffer::~CDVDVideoCodecIMXBuffer() + { + assert(m_refs == 0); +@@ -1149,23 +1185,29 @@ bool CDVDVideoCodecIPUBuffer::IsValid() + return m_source && m_source->IsValid() && m_pPhyAddr; + } + +-bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffer, +- CDVDVideoCodecBuffer *previousBuffer, VpuFieldType fieldType) ++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 = currentBuffer->iWidth; +- iHeight = currentBuffer->iHeight; ++ 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; +- task.input.paddr = (int)GET_PHYS_ADDR(currentBuffer); + + // Output is our IPU buffer + task.output.width = iWidth; +@@ -1173,29 +1215,32 @@ bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffe + task.output.format = IPU_PIX_FMT_NV12; + task.output.paddr = (int)GET_PHYS_ADDR(this); + +- // Fill previous buffer address +- if (previousBuffer) +- task.input.paddr_n = (int)GET_PHYS_ADDR(previousBuffer); ++ // 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.motion = task.input.paddr_n?LOW_MOTION:HIGH_MOTION; ++ task.input.deinterlace.field_fmt = fieldFmt; + + switch (fieldType) + { + case VPU_FIELD_TOP: +- task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_TOP; +- break; +- case VPU_FIELD_BOTTOM: +- task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM; +- break; +- /* + case VPU_FIELD_TB: +- task.input.deinterlace.field_fmt = IPU_DEINTERLACE_FIELD_TOP; ++ 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; ++ task.input.deinterlace.field_fmt |= IPU_DEINTERLACE_FIELD_BOTTOM; + break; +- */ + default: + break; + } +@@ -1213,16 +1258,16 @@ bool CDVDVideoCodecIPUBuffer::Process(int fd, CDVDVideoCodecBuffer *currentBuffe + return false; + } + +- currentBuffer->Lock(); ++ 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 = currentBuffer; ++ m_source = buffer; + m_source->Lock(); + +- currentBuffer->Release(); ++ buffer->Release(); + + return true; + } +@@ -1321,7 +1366,7 @@ CDVDVideoCodecIPUBuffers::CDVDVideoCodecIPUBuffers() + : m_ipuHandle(0) + , m_bufferNum(0) + , m_buffers(NULL) +- , m_lastBuffer(NULL) ++ , m_currentFieldFmt(0) + { + } + +@@ -1349,6 +1394,7 @@ bool CDVDVideoCodecIPUBuffers::Init(int width, int height, int numBuffers, int n + + m_bufferNum = numBuffers; + m_buffers = new CDVDVideoCodecIPUBuffer*[m_bufferNum]; ++ m_currentFieldFmt = 0; + + for (int i=0; i < m_bufferNum; i++) + { +@@ -1369,9 +1415,9 @@ bool CDVDVideoCodecIPUBuffers::Init(int width, int height, int numBuffers, int n + + bool CDVDVideoCodecIPUBuffers::Reset() + { +- SAFE_RELEASE(m_lastBuffer); + for (int i=0; i < m_bufferNum; i++) + m_buffers[i]->ReleaseFrameBuffer(); ++ m_currentFieldFmt = 0; + } + + bool CDVDVideoCodecIPUBuffers::Close() +@@ -1407,7 +1453,6 @@ bool CDVDVideoCodecIPUBuffers::Close() + } + + m_bufferNum = 0; +- SAFE_RELEASE(m_lastBuffer); + return true; + } + +@@ -1418,7 +1463,8 @@ CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer, + CDVDVideoCodecIPUBuffer *target = NULL; + bool ret = true; + +- if (!m_bufferNum) ++ // TODO: Needs further checks on real streams ++ if (!m_bufferNum /*|| (fieldType == VPU_FIELD_NONE)*/) + return NULL; + + for (int i=0; i < m_bufferNum; i++ ) +@@ -1428,8 +1474,9 @@ CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer, + // IPU process: + // SRC: Current VPU physical buffer address + last VPU buffer address + // DST: IPU buffer[i] +- CDVDVideoCodecBuffer *last = lowMotion?m_lastBuffer:NULL; +- ret = m_buffers[i]->Process(m_ipuHandle, sourceBuffer, last, fieldType); ++ ret = m_buffers[i]->Process(m_ipuHandle, (CDVDVideoCodecIMXBuffer*)sourceBuffer, ++ fieldType, m_currentFieldFmt/* | IPU_DEINTERLACE_RATE_EN*/, ++ lowMotion); + if (ret) + { + #ifdef TRACE_FRAMES +@@ -1447,10 +1494,8 @@ CDVDVideoCodecIPUBuffers::Process(CDVDVideoCodecBuffer *sourceBuffer, + CLog::Log(LOGERROR, "Deinterlacing: did not find free buffer, forward unprocessed frame\n"); + } + +- SAFE_RELEASE(m_lastBuffer); +- m_lastBuffer = sourceBuffer; +- if (m_lastBuffer != NULL) +- m_lastBuffer->Lock(); ++ // Toggle frame index bit ++ //m_currentFieldFmt ^= IPU_DEINTERLACE_RATE_FRAME1; + + return target; + } +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +index a76575f..05722ce 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h +@@ -66,12 +66,14 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + virtual bool IsValid(); + + bool Rendered() const; +- void Queue(VpuDecOutFrameInfo *frameInfo); ++ void Queue(VpuDecOutFrameInfo *frameInfo, ++ CDVDVideoCodecIMXBuffer *previous); + VpuDecRetCode ReleaseFramebuffer(VpuDecHandle *handle); + void SetPts(double pts); + double GetPts(void) const; ++ CDVDVideoCodecIMXBuffer *GetPreviousBuffer() const; + +-protected: ++private: + // private because we are reference counted + virtual ~CDVDVideoCodecIMXBuffer(); + +@@ -83,6 +85,8 @@ class CDVDVideoCodecIMXBuffer : public CDVDVideoCodecBuffer + 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 +@@ -103,8 +107,9 @@ class CDVDVideoCodecIPUBuffer : public CDVDVideoCodecBuffer + + // Returns whether the buffer is ready to be used + bool Rendered() const { return m_source == NULL; } +- bool Process(int fd, CDVDVideoCodecBuffer *currentBuffer, +- CDVDVideoCodecBuffer *previousBuffer, VpuFieldType fieldType); ++ bool Process(int fd, CDVDVideoCodecIMXBuffer *buffer, ++ VpuFieldType fieldType, int fieldFmt, ++ bool lowMotion); + void ReleaseFrameBuffer(); + + bool Allocate(int fd, int width, int height, int nAlign); +@@ -146,7 +151,7 @@ class CDVDVideoCodecIPUBuffers + int m_ipuHandle; + int m_bufferNum; + CDVDVideoCodecIPUBuffer **m_buffers; +- CDVDVideoCodecBuffer *m_lastBuffer; ++ int m_currentFieldFmt; + }; + + +@@ -181,31 +186,30 @@ class CDVDVideoCodecIMX : public CDVDVideoCodec + bool VpuAllocFrameBuffers(); + int VpuFindBuffer(void *frameAddr); + +- static const int m_extraVpuBuffers; // Number of additional buffers for VPU +- static const int m_maxVpuDecodeLoops; // Maximum iterations in VPU decoding loop +- static CCriticalSection m_codecBufferLock; +- +- 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 ++ 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; +- VpuMemDesc *m_extraMem; // Table of allocated extra Memory +-// VpuMemDesc *m_outputBuffers; // Table of buffers out of VPU (used to call properly VPU_DecOutFrameDisplayed) +- int m_frameCounter; // Decoded frames counter +- bool m_usePTS; // State whether pts out of decoding process should be used +- int m_modeDeinterlace; // Deinterlacer mode: 0=off, 1=high, 2..=low +- 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 ++ 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 + }; +-- +1.9.3 + + +From 183ecc207f0785bfa319038225a3227a7d249442 Mon Sep 17 00:00:00 2001 +From: Thomas Genty +Date: Sun, 6 Apr 2014 13:57:12 +0200 +Subject: [PATCH 48/56] detect imx device on all platform using file + /sys/class/graphics/fb0/fsl_disp_dev_property + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 4ffa708..404bd3c 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -33,6 +33,7 @@ + #include "guilib/gui3d.h" + #include "windowing/WindowingFactory.h" + #include "cores/AudioEngine/AEFactory.h" ++#include + + CEGLNativeTypeIMX::CEGLNativeTypeIMX() + : m_display(NULL) +@@ -46,14 +47,11 @@ CEGLNativeTypeIMX::~CEGLNativeTypeIMX() + + bool CEGLNativeTypeIMX::CheckCompatibility() + { +- std::string strName; +- std::string str2 ("mxc_sdc_fb"); +- get_sysfs_str("/sys/class/graphics/fb0/device/modalias", strName); +- StringUtils::Trim(strName); +- size_t found = strName.find(str2); +- if (found!=std::string::npos) ++ std::ifstream file("/sys/class/graphics/fb0/fsl_disp_dev_property"); ++ if (!file) ++ return false; ++ else + return true; +- return false; + } + + void CEGLNativeTypeIMX::Initialize() +-- +1.9.3 + + +From 14d71c83c774b65a527025681fc08b0544006c0c Mon Sep 17 00:00:00 2001 +From: Thomas Genty +Date: Tue, 8 Apr 2014 19:02:52 +0200 +Subject: [PATCH 49/56] detect imx device on all platforms (try2) + +--- + xbmc/windowing/egl/EGLNativeTypeIMX.cpp | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +index 404bd3c..3dc64a3 100644 +--- a/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ++++ b/xbmc/windowing/egl/EGLNativeTypeIMX.cpp +@@ -48,10 +48,7 @@ CEGLNativeTypeIMX::~CEGLNativeTypeIMX() + bool CEGLNativeTypeIMX::CheckCompatibility() + { + std::ifstream file("/sys/class/graphics/fb0/fsl_disp_dev_property"); +- if (!file) +- return false; +- else +- return true; ++ return file; + } + + void CEGLNativeTypeIMX::Initialize() +-- +1.9.3 + + +From 0579a8528e58eb21f18ba74b038cde305c8e1b02 Mon Sep 17 00:00:00 2001 +From: warped-rudi +Date: Mon, 14 Apr 2014 08:07:14 +0200 +Subject: [PATCH 50/56] Fix sample conversion from signed 24bit big-endian to + float + +--- + xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +index d113f09..9454f7d 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +@@ -244,7 +244,7 @@ unsigned int CAEConvert::S24BE3_Float(uint8_t *data, const unsigned int samples, + { + for (unsigned int i = 0; i < samples; ++i, data += 3) + { +- int s = (data[1] << 24) | (data[2] << 16) | (data[3] << 8); ++ int s = (data[0] << 24) | (data[1] << 16) | (data[2] << 8); + *dest++ = (float)s * INT32_SCALE; + } + return samples; +-- +1.9.3 + + +From 2ad3b9b2edf82be39a8b148da41716c5d42dc9f5 Mon Sep 17 00:00:00 2001 +From: warped-rudi +Date: Tue, 15 Apr 2014 15:41:59 +0200 +Subject: [PATCH 51/56] Rename AE_FMT_S24xE4 to AE_FMT_S24xE4H to indicate + upper 3 bytes are used + +--- + .../AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp | 8 ++++---- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++-- + xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp | 12 ++++++------ + xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp | 6 +++--- + xbmc/cores/AudioEngine/Utils/AEAudioFormat.h | 8 ++++---- + xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 16 ++++++++-------- + xbmc/cores/AudioEngine/Utils/AEConvert.h | 6 +++--- + xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 10 +++++----- + 8 files changed, 35 insertions(+), 35 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +index 6478f3a..d40c096 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +@@ -281,14 +281,14 @@ AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) + if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8; + else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; + else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; +- else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_S24NE4H) return AV_SAMPLE_FMT_S32; + else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; + else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; + + else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P; + else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; + else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; +- else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P; ++ else if (format == AE_FMT_S24NE4HP) return AV_SAMPLE_FMT_S32P; + else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; + else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; + +@@ -300,14 +300,14 @@ AEDataFormat CActiveAEResample::GetAESampleFormat(AVSampleFormat format, int bit + if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8; + else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE; + else if (format == AV_SAMPLE_FMT_S32 && bits == 32) return AE_FMT_S32NE; +- else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4; ++ else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4H; + else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT; + else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE; + + else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P; + else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP; + else if (format == AV_SAMPLE_FMT_S32P && bits == 32) return AE_FMT_S32NEP; +- else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4P; ++ else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4HP; + else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP; + else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP; + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index 8c0bad6..baa5dbe 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -268,7 +268,7 @@ snd_pcm_format_t CAESinkALSA::AEFormatToALSAFormat(const enum AEDataFormat forma + case AE_FMT_S16NE : return SND_PCM_FORMAT_S16; + case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE; + case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE; +- case AE_FMT_S24NE4: return SND_PCM_FORMAT_S24; ++ case AE_FMT_S24NE4H: return SND_PCM_FORMAT_S24; + #ifdef __BIG_ENDIAN__ + case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE; + #else +@@ -343,7 +343,7 @@ bool CAESinkALSA::InitializeHW(const ALSAConfig &inconfig, ALSAConfig &outconfig + { + /* if we opened in 32bit and only have 24bits, pack into 24 */ + if (fmtBits == 32 && bits == 24) +- i = AE_FMT_S24NE4; ++ i = AE_FMT_S24NE4H; + else + continue; + } +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp +index 54af197..67e6104 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp +@@ -80,9 +80,9 @@ static pa_sample_format AEFormatToPulseFormat(AEDataFormat format) + case AE_FMT_S24LE3: return PA_SAMPLE_S24LE; + case AE_FMT_S24BE3: return PA_SAMPLE_S24BE; + case AE_FMT_S24NE3: return PA_SAMPLE_S24NE; +- case AE_FMT_S24LE4: return PA_SAMPLE_S24_32LE; +- case AE_FMT_S24BE4: return PA_SAMPLE_S24_32BE; +- case AE_FMT_S24NE4: return PA_SAMPLE_S24_32NE; ++ case AE_FMT_S24LE4H: return PA_SAMPLE_S24_32LE; ++ case AE_FMT_S24BE4H: return PA_SAMPLE_S24_32BE; ++ case AE_FMT_S24NE4H: return PA_SAMPLE_S24_32NE; + case AE_FMT_S32BE : return PA_SAMPLE_S32BE; + case AE_FMT_S32LE : return PA_SAMPLE_S32LE; + case AE_FMT_S32NE : return PA_SAMPLE_S32NE; +@@ -119,9 +119,9 @@ static AEDataFormat defaultDataFormats[] = { + AE_FMT_S24LE3, + AE_FMT_S24BE3, + AE_FMT_S24NE3, +- AE_FMT_S24LE4, +- AE_FMT_S24BE4, +- AE_FMT_S24NE4, ++ AE_FMT_S24LE4H, ++ AE_FMT_S24BE4H, ++ AE_FMT_S24NE4H, + AE_FMT_S32BE, + AE_FMT_S32LE, + AE_FMT_S32NE, +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +index e895dd2..df3c385 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +@@ -111,7 +111,7 @@ struct sampleFormat + /* Sample formats go from float -> 32 bit int -> 24 bit int (packed in 32) -> -> 24 bit int -> 16 bit int */ + static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, AE_FMT_FLOAT}, + {KSDATAFORMAT_SUBTYPE_PCM, 32, 32, AE_FMT_S32NE}, +- {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4}, ++ {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4H}, + {KSDATAFORMAT_SUBTYPE_PCM, 24, 24, AE_FMT_S24NE3}, + {KSDATAFORMAT_SUBTYPE_PCM, 16, 16, AE_FMT_S16NE} }; + +@@ -758,7 +758,7 @@ void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool fo + wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p); + wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); + wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; +- if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4) ++ if (p <= AE_FMT_S24NE4H && p >= AE_FMT_S24BE4H) + { + wfxex.Samples.wValidBitsPerSample = 24; + } +@@ -1149,7 +1149,7 @@ bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format) + else if (wfxex.Samples.wValidBitsPerSample == 32) + format.m_dataFormat = AE_FMT_S32NE; + else +- format.m_dataFormat = AE_FMT_S24NE4; ++ format.m_dataFormat = AE_FMT_S24NE4H; + } + else if (wfxex.Format.wBitsPerSample == 24) + format.m_dataFormat = AE_FMT_S24NE3; +diff --git a/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h b/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h +index 9ac5c79..10576bf 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h ++++ b/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h +@@ -41,9 +41,9 @@ enum AEDataFormat + AE_FMT_S32LE, + AE_FMT_S32NE, + +- AE_FMT_S24BE4, +- AE_FMT_S24LE4, +- AE_FMT_S24NE4, /* S24 in 4 bytes */ ++ AE_FMT_S24BE4H, ++ AE_FMT_S24LE4H, ++ AE_FMT_S24NE4H, /* S24 in upper 4 bytes */ + + AE_FMT_S24BE3, + AE_FMT_S24LE3, +@@ -65,7 +65,7 @@ enum AEDataFormat + AE_FMT_U8P, + AE_FMT_S16NEP, + AE_FMT_S32NEP, +- AE_FMT_S24NE4P, ++ AE_FMT_S24NE4HP, + AE_FMT_S24NE3P, + AE_FMT_DOUBLEP, + AE_FMT_FLOATP, +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +index 9454f7d..31e025a 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +@@ -69,18 +69,18 @@ CAEConvert::AEConvertToFn CAEConvert::ToFloat(enum AEDataFormat dataFormat) + #ifdef __BIG_ENDIAN__ + case AE_FMT_S16NE : return &S16BE_Float; + case AE_FMT_S32NE : return &S32BE_Float; +- case AE_FMT_S24NE4: return &S24BE4_Float; ++ case AE_FMT_S24NE4H: return &S24BE4H_Float; + case AE_FMT_S24NE3: return &S24BE3_Float; + #else + case AE_FMT_S16NE : return &S16LE_Float; + case AE_FMT_S32NE : return &S32LE_Float; +- case AE_FMT_S24NE4: return &S24LE4_Float; ++ case AE_FMT_S24NE4H: return &S24LE4H_Float; + case AE_FMT_S24NE3: return &S24LE3_Float; + #endif + case AE_FMT_S16LE : return &S16LE_Float; + case AE_FMT_S16BE : return &S16BE_Float; +- case AE_FMT_S24LE4: return &S24LE4_Float; +- case AE_FMT_S24BE4: return &S24BE4_Float; ++ case AE_FMT_S24LE4H: return &S24LE4H_Float; ++ case AE_FMT_S24BE4H: return &S24BE4H_Float; + case AE_FMT_S24LE3: return &S24LE3_Float; + case AE_FMT_S24BE3: return &S24BE3_Float; + #if defined(__ARM_NEON__) +@@ -112,7 +112,7 @@ CAEConvert::AEConvertFrFn CAEConvert::FrFloat(enum AEDataFormat dataFormat) + #endif + case AE_FMT_S16LE : return &Float_S16LE; + case AE_FMT_S16BE : return &Float_S16BE; +- case AE_FMT_S24NE4: return &Float_S24NE4; ++ case AE_FMT_S24NE4H: return &Float_S24NE4H; + case AE_FMT_S24NE3: return &Float_S24NE3; + #if defined(__ARM_NEON__) + case AE_FMT_S32LE : return &Float_S32LE_Neon; +@@ -210,7 +210,7 @@ unsigned int CAEConvert::S16BE_Float(uint8_t* data, const unsigned int samples, + return samples; + } + +-unsigned int CAEConvert::S24LE4_Float(uint8_t *data, const unsigned int samples, float *dest) ++unsigned int CAEConvert::S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest) + { + for (unsigned int i = 0; i < samples; ++i, data += 4) + { +@@ -220,7 +220,7 @@ unsigned int CAEConvert::S24LE4_Float(uint8_t *data, const unsigned int samples, + return samples; + } + +-unsigned int CAEConvert::S24BE4_Float(uint8_t *data, const unsigned int samples, float *dest) ++unsigned int CAEConvert::S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest) + { + for (unsigned int i = 0; i < samples; ++i, data += 4) + { +@@ -786,7 +786,7 @@ unsigned int CAEConvert::Float_S16BE(float *data, const unsigned int samples, ui + return samples << 1; + } + +-unsigned int CAEConvert::Float_S24NE4(float *data, const unsigned int samples, uint8_t *dest) ++unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest) + { + int32_t *dst = (int32_t*)dest; + #ifdef __SSE2__ +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.h b/xbmc/cores/AudioEngine/Utils/AEConvert.h +index 7ded823..cf547c8 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.h ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.h +@@ -28,8 +28,8 @@ class CAEConvert{ + static unsigned int S8_Float (uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S16LE_Float (uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S16BE_Float (uint8_t *data, const unsigned int samples, float *dest); +- static unsigned int S24LE4_Float(uint8_t *data, const unsigned int samples, float *dest); +- static unsigned int S24BE4_Float(uint8_t *data, const unsigned int samples, float *dest); ++ static unsigned int S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest); ++ static unsigned int S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S24BE3_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S32LE_Float (uint8_t *data, const unsigned int samples, float *dest); +@@ -41,7 +41,7 @@ class CAEConvert{ + static unsigned int Float_S8 (float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S16LE (float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S16BE (float *data, const unsigned int samples, uint8_t *dest); +- static unsigned int Float_S24NE4(float *data, const unsigned int samples, uint8_t *dest); ++ static unsigned int Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S24NE3(float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S32LE (float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S32BE (float *data, const unsigned int samples, uint8_t *dest); +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +index feaa621..a70f20c 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +@@ -125,7 +125,7 @@ const unsigned int CAEUtil::DataFormatToBits(const enum AEDataFormat dataFormat) + + const unsigned int CAEUtil::DataFormatToUsedBits(const enum AEDataFormat dataFormat) + { +- if (dataFormat == AE_FMT_S24BE4 || dataFormat == AE_FMT_S24LE4 || dataFormat == AE_FMT_S24NE4) ++ if (dataFormat == AE_FMT_S24BE4H || dataFormat == AE_FMT_S24LE4H || dataFormat == AE_FMT_S24NE4H) + return 24; + else + return DataFormatToBits(dataFormat); +@@ -149,9 +149,9 @@ const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat) + "AE_FMT_S32LE", + "AE_FMT_S32NE", + +- "AE_FMT_S24BE4", +- "AE_FMT_S24LE4", +- "AE_FMT_S24NE4", /* S24 in 4 bytes */ ++ "AE_FMT_S24BE4H", ++ "AE_FMT_S24LE4H", ++ "AE_FMT_S24NE4H", /* S24 in 4 bytes */ + + "AE_FMT_S24BE3", + "AE_FMT_S24LE3", +@@ -173,7 +173,7 @@ const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat) + "AE_FMT_U8P", + "AE_FMT_S16NEP", + "AE_FMT_S32NEP", +- "AE_FMT_S24NE4P", ++ "AE_FMT_S24NE4HP", + "AE_FMT_S24NE3P", + "AE_FMT_DOUBLEP", + "AE_FMT_FLOATP" +-- +1.9.3 + + +From 9dc9d38c8a8823a2af32714f98b8559e3fe50cc0 Mon Sep 17 00:00:00 2001 +From: warped-rudi +Date: Tue, 15 Apr 2014 16:15:05 +0200 +Subject: [PATCH 52/56] Make S24xE4H conversions always act on upper 3 bytes + +--- + xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +index 31e025a..3222af2 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +@@ -214,7 +214,7 @@ unsigned int CAEConvert::S24LE4H_Float(uint8_t *data, const unsigned int samples + { + for (unsigned int i = 0; i < samples; ++i, data += 4) + { +- int s = (data[2] << 24) | (data[1] << 16) | (data[0] << 8); ++ int s = (data[3] << 24) | (data[2] << 16) | (data[1] << 8); + *dest++ = (float)s * INT32_SCALE; + } + return samples; +@@ -841,7 +841,7 @@ unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, + _mm_empty(); + #else /* no SSE2 */ + for (uint32_t i = 0; i < samples; ++i) +- *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0x00FFFFFF; ++ *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) << 8; + #endif + + return samples << 2; +-- +1.9.3 + + +From d21209b7066ed7d11ad56f754b13d5c2612a4d99 Mon Sep 17 00:00:00 2001 +From: warped-rudi +Date: Tue, 15 Apr 2014 17:56:51 +0200 +Subject: [PATCH 53/56] Introduce new formats AE_FMT_S24xE4L which use the + lower 3 bytes of a 4 byte word + +--- + xbmc/cores/AudioEngine/Utils/AEAudioFormat.h | 5 ++ + xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 87 ++++++++++++++++++++++++++++ + xbmc/cores/AudioEngine/Utils/AEConvert.h | 3 + + xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 25 +++++--- + 4 files changed, 113 insertions(+), 7 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h b/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h +index 10576bf..0916abb 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h ++++ b/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h +@@ -45,6 +45,10 @@ enum AEDataFormat + AE_FMT_S24LE4H, + AE_FMT_S24NE4H, /* S24 in upper 4 bytes */ + ++ AE_FMT_S24BE4L, ++ AE_FMT_S24LE4L, ++ AE_FMT_S24NE4L, /* S24 in lower 4 bytes */ ++ + AE_FMT_S24BE3, + AE_FMT_S24LE3, + AE_FMT_S24NE3, /* S24 in 3 bytes */ +@@ -66,6 +70,7 @@ enum AEDataFormat + AE_FMT_S16NEP, + AE_FMT_S32NEP, + AE_FMT_S24NE4HP, ++ AE_FMT_S24NE4LP, + AE_FMT_S24NE3P, + AE_FMT_DOUBLEP, + AE_FMT_FLOATP, +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +index 3222af2..b454a20 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +@@ -70,17 +70,21 @@ CAEConvert::AEConvertToFn CAEConvert::ToFloat(enum AEDataFormat dataFormat) + case AE_FMT_S16NE : return &S16BE_Float; + case AE_FMT_S32NE : return &S32BE_Float; + case AE_FMT_S24NE4H: return &S24BE4H_Float; ++ case AE_FMT_S24NE4L: return &S24BE4L_Float; + case AE_FMT_S24NE3: return &S24BE3_Float; + #else + case AE_FMT_S16NE : return &S16LE_Float; + case AE_FMT_S32NE : return &S32LE_Float; + case AE_FMT_S24NE4H: return &S24LE4H_Float; ++ case AE_FMT_S24NE4L: return &S24LE4L_Float; + case AE_FMT_S24NE3: return &S24LE3_Float; + #endif + case AE_FMT_S16LE : return &S16LE_Float; + case AE_FMT_S16BE : return &S16BE_Float; + case AE_FMT_S24LE4H: return &S24LE4H_Float; ++ case AE_FMT_S24LE4L: return &S24LE4L_Float; + case AE_FMT_S24BE4H: return &S24BE4H_Float; ++ case AE_FMT_S24BE4L: return &S24BE4L_Float; + case AE_FMT_S24LE3: return &S24LE3_Float; + case AE_FMT_S24BE3: return &S24BE3_Float; + #if defined(__ARM_NEON__) +@@ -113,6 +117,7 @@ CAEConvert::AEConvertFrFn CAEConvert::FrFloat(enum AEDataFormat dataFormat) + case AE_FMT_S16LE : return &Float_S16LE; + case AE_FMT_S16BE : return &Float_S16BE; + case AE_FMT_S24NE4H: return &Float_S24NE4H; ++ case AE_FMT_S24NE4L: return &Float_S24NE4L; + case AE_FMT_S24NE3: return &Float_S24NE3; + #if defined(__ARM_NEON__) + case AE_FMT_S32LE : return &Float_S32LE_Neon; +@@ -220,6 +225,16 @@ unsigned int CAEConvert::S24LE4H_Float(uint8_t *data, const unsigned int samples + return samples; + } + ++unsigned int CAEConvert::S24LE4L_Float(uint8_t *data, const unsigned int samples, float *dest) ++{ ++ for (unsigned int i = 0; i < samples; ++i, data += 4) ++ { ++ int s = (data[2] << 24) | (data[1] << 16) | (data[0] << 8); ++ *dest++ = (float)s * INT32_SCALE; ++ } ++ return samples; ++} ++ + unsigned int CAEConvert::S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest) + { + for (unsigned int i = 0; i < samples; ++i, data += 4) +@@ -230,6 +245,16 @@ unsigned int CAEConvert::S24BE4H_Float(uint8_t *data, const unsigned int samples + return samples; + } + ++unsigned int CAEConvert::S24BE4L_Float(uint8_t *data, const unsigned int samples, float *dest) ++{ ++ for (unsigned int i = 0; i < samples; ++i, data += 4) ++ { ++ int s = (data[1] << 24) | (data[2] << 16) | (data[3] << 8); ++ *dest++ = (float)s * INT32_SCALE; ++ } ++ return samples; ++} ++ + unsigned int CAEConvert::S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest) + { + for (unsigned int i = 0; i < samples; ++i, data += 3) +@@ -847,6 +872,68 @@ unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, + return samples << 2; + } + ++unsigned int CAEConvert::Float_S24NE4L(float *data, const unsigned int samples, uint8_t *dest) ++{ ++ int32_t *dst = (int32_t*)dest; ++ #ifdef __SSE2__ ++ ++ const __m128i msk = _mm_set1_epi32(0xFFFFFF); ++ const __m128 mul = _mm_set_ps1((float)INT24_MAX+.5f); ++ unsigned int count = samples; ++ ++ /* work around invalid alignment */ ++ while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) ++ { ++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF; ++ ++data; ++ ++dst; ++ --count; ++ } ++ ++ const uint32_t even = count & ~0x3; ++ for (uint32_t i = 0; i < even; i += 4, data += 4, dst += 4) ++ { ++ __m128 in = _mm_mul_ps(_mm_load_ps(data), mul); ++ __m128i con = _mm_cvtps_epi32(in); ++ con = _mm_and_si128(con, msk); ++ memcpy(dst, &con, sizeof(int32_t) * 4); ++ } ++ ++ if (count != even) ++ { ++ const uint32_t odd = count - even; ++ if (odd == 1) ++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF; ++ else ++ { ++ __m128 in; ++ if (odd == 2) ++ { ++ in = _mm_setr_ps(data[0], data[1], 0, 0); ++ in = _mm_mul_ps(in, mul); ++ __m128i con = _mm_cvtps_epi32(in); ++ con = _mm_and_si128(con, msk); ++ memcpy(dst, &con, sizeof(int32_t) * 2); ++ } ++ else ++ { ++ in = _mm_setr_ps(data[0], data[1], data[2], 0); ++ in = _mm_mul_ps(in, mul); ++ __m128i con = _mm_cvtps_epi32(in); ++ con = _mm_and_si128(con, msk); ++ memcpy(dst, &con, sizeof(int32_t) * 3); ++ } ++ } ++ } ++ _mm_empty(); ++ #else /* no SSE2 */ ++ for (uint32_t i = 0; i < samples; ++i) ++ *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0xFFFFFF; ++ #endif ++ ++ return samples << 2; ++} ++ + unsigned int CAEConvert::Float_S24NE3(float *data, const unsigned int samples, uint8_t *dest) + { + /* We do not want to shift for S24LE3, since left-shifting would actually +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.h b/xbmc/cores/AudioEngine/Utils/AEConvert.h +index cf547c8..82afd4b 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.h ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.h +@@ -29,7 +29,9 @@ class CAEConvert{ + static unsigned int S16LE_Float (uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S16BE_Float (uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest); ++ static unsigned int S24LE4L_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest); ++ static unsigned int S24BE4L_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S24BE3_Float(uint8_t *data, const unsigned int samples, float *dest); + static unsigned int S32LE_Float (uint8_t *data, const unsigned int samples, float *dest); +@@ -42,6 +44,7 @@ class CAEConvert{ + static unsigned int Float_S16LE (float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S16BE (float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest); ++ static unsigned int Float_S24NE4L(float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S24NE3(float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S32LE (float *data, const unsigned int samples, uint8_t *dest); + static unsigned int Float_S32BE (float *data, const unsigned int samples, uint8_t *dest); +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +index a70f20c..095fc8f 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +@@ -92,9 +92,13 @@ const unsigned int CAEUtil::DataFormatToBits(const enum AEDataFormat dataFormat) + 32, /* S32LE */ + 32, /* S32NE */ + +- 32, /* S24BE */ +- 32, /* S24LE */ +- 32, /* S24NE */ ++ 32, /* S24BE4H */ ++ 32, /* S24LE4H */ ++ 32, /* S24NE4H */ ++ ++ 32, /* S24BE4L */ ++ 32, /* S24LE4L */ ++ 32, /* S24NE4L */ + + 24, /* S24BE3 */ + 24, /* S24LE3 */ +@@ -114,8 +118,9 @@ const unsigned int CAEUtil::DataFormatToBits(const enum AEDataFormat dataFormat) + 8, /* U8P */ + 16, /* S16NEP */ + 32, /* S32NEP */ +- 32, /* S24NEP */ +- 24, /* S24NE3P*/ ++ 32, /* S24NE4HP */ ++ 32, /* S24NE4LP */ ++ 24, /* S24NE3P */ + sizeof(double) << 3, /* DOUBLEP */ + sizeof(float ) << 3 /* FLOATP */ + }; +@@ -125,7 +130,8 @@ const unsigned int CAEUtil::DataFormatToBits(const enum AEDataFormat dataFormat) + + const unsigned int CAEUtil::DataFormatToUsedBits(const enum AEDataFormat dataFormat) + { +- if (dataFormat == AE_FMT_S24BE4H || dataFormat == AE_FMT_S24LE4H || dataFormat == AE_FMT_S24NE4H) ++ if (dataFormat == AE_FMT_S24BE4H || dataFormat == AE_FMT_S24LE4H || dataFormat == AE_FMT_S24NE4H || ++ dataFormat == AE_FMT_S24BE4L || dataFormat == AE_FMT_S24LE4L || dataFormat == AE_FMT_S24NE4L) + return 24; + else + return DataFormatToBits(dataFormat); +@@ -151,7 +157,11 @@ const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat) + + "AE_FMT_S24BE4H", + "AE_FMT_S24LE4H", +- "AE_FMT_S24NE4H", /* S24 in 4 bytes */ ++ "AE_FMT_S24NE4H", /* S24 in upper 4 bytes */ ++ ++ "AE_FMT_S24BE4L", ++ "AE_FMT_S24LE4L", ++ "AE_FMT_S24NE4L", /* S24 in lower 4 bytes */ + + "AE_FMT_S24BE3", + "AE_FMT_S24LE3", +@@ -174,6 +184,7 @@ const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat) + "AE_FMT_S16NEP", + "AE_FMT_S32NEP", + "AE_FMT_S24NE4HP", ++ "AE_FMT_S24NE4LP", + "AE_FMT_S24NE3P", + "AE_FMT_DOUBLEP", + "AE_FMT_FLOATP" +-- +1.9.3 + + +From b638d524250f7928f8d6d8566072c3219fcd4321 Mon Sep 17 00:00:00 2001 +From: warped-rudi +Date: Tue, 15 Apr 2014 18:14:27 +0200 +Subject: [PATCH 54/56] Use AE_FMT_S24xE4L in conjunction with ALSA and + PulseAudio + +--- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++-- + xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp | 12 ++++++------ + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index baa5dbe..3270bc9 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -268,7 +268,7 @@ snd_pcm_format_t CAESinkALSA::AEFormatToALSAFormat(const enum AEDataFormat forma + case AE_FMT_S16NE : return SND_PCM_FORMAT_S16; + case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE; + case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE; +- case AE_FMT_S24NE4H: return SND_PCM_FORMAT_S24; ++ case AE_FMT_S24NE4L: return SND_PCM_FORMAT_S24; + #ifdef __BIG_ENDIAN__ + case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE; + #else +@@ -343,7 +343,7 @@ bool CAESinkALSA::InitializeHW(const ALSAConfig &inconfig, ALSAConfig &outconfig + { + /* if we opened in 32bit and only have 24bits, pack into 24 */ + if (fmtBits == 32 && bits == 24) +- i = AE_FMT_S24NE4H; ++ i = AE_FMT_S24NE4L; + else + continue; + } +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp +index 67e6104..c6a39c2 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp +@@ -80,9 +80,9 @@ static pa_sample_format AEFormatToPulseFormat(AEDataFormat format) + case AE_FMT_S24LE3: return PA_SAMPLE_S24LE; + case AE_FMT_S24BE3: return PA_SAMPLE_S24BE; + case AE_FMT_S24NE3: return PA_SAMPLE_S24NE; +- case AE_FMT_S24LE4H: return PA_SAMPLE_S24_32LE; +- case AE_FMT_S24BE4H: return PA_SAMPLE_S24_32BE; +- case AE_FMT_S24NE4H: return PA_SAMPLE_S24_32NE; ++ case AE_FMT_S24LE4L: return PA_SAMPLE_S24_32LE; ++ case AE_FMT_S24BE4L: return PA_SAMPLE_S24_32BE; ++ case AE_FMT_S24NE4L: return PA_SAMPLE_S24_32NE; + case AE_FMT_S32BE : return PA_SAMPLE_S32BE; + case AE_FMT_S32LE : return PA_SAMPLE_S32LE; + case AE_FMT_S32NE : return PA_SAMPLE_S32NE; +@@ -119,9 +119,9 @@ static AEDataFormat defaultDataFormats[] = { + AE_FMT_S24LE3, + AE_FMT_S24BE3, + AE_FMT_S24NE3, +- AE_FMT_S24LE4H, +- AE_FMT_S24BE4H, +- AE_FMT_S24NE4H, ++ AE_FMT_S24LE4L, ++ AE_FMT_S24BE4L, ++ AE_FMT_S24NE4L, + AE_FMT_S32BE, + AE_FMT_S32LE, + AE_FMT_S32NE, +-- +1.9.3 + + +From 7003558c899666d2d24e6f069d3cf65835538c7e Mon Sep 17 00:00:00 2001 +From: Rudi +Date: Tue, 15 Apr 2014 21:59:39 +0200 +Subject: [PATCH 55/56] Remove unneccessary mask operations in Float_S24NE4H + +--- + xbmc/cores/AudioEngine/Utils/AEConvert.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +index b454a20..c2bafb8 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEConvert.cpp +@@ -822,7 +822,7 @@ unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, + /* work around invalid alignment */ + while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) + { +- dst[0] = (safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8; ++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) << 8; + ++data; + ++dst; + --count; +@@ -841,7 +841,7 @@ unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, + { + const uint32_t odd = count - even; + if (odd == 1) +- dst[0] = (safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8; ++ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) << 8; + else + { + __m128 in; +-- +1.9.3 + + +From fb025071366c170bc9dc03884cdbee06f8b48d5e Mon Sep 17 00:00:00 2001 +From: Rudi +Date: Tue, 15 Apr 2014 23:12:49 +0200 +Subject: [PATCH 56/56] Avoid intermediate floating point conversion when + outputting S24NE4L + +--- + .../Engines/ActiveAE/ActiveAEResample.cpp | 2 + + .../AudioEngine/Engines/ActiveAE/ActiveAESink.cpp | 55 ++++++++++++++++++---- + .../AudioEngine/Engines/ActiveAE/ActiveAESink.h | 2 + + 3 files changed, 50 insertions(+), 9 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +index d40c096..9bf017d 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +@@ -282,6 +282,7 @@ AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) + else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; + else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; + else if (format == AE_FMT_S24NE4H) return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_S24NE4L) return AV_SAMPLE_FMT_S32; + else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; + else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; + +@@ -289,6 +290,7 @@ AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) + else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; + else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; + else if (format == AE_FMT_S24NE4HP) return AV_SAMPLE_FMT_S32P; ++ else if (format == AE_FMT_S24NE4LP) return AV_SAMPLE_FMT_S32P; + else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; + else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; + +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp +index 56b72d3..ca31516 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp +@@ -796,6 +796,12 @@ void CActiveAESink::ReturnBuffers() + } + } + ++static inline void RShift8_32_buf(uint32_t *src, uint32_t *dst, uint32_t count) ++{ ++ while (count--) ++ *dst++ = *src++ >> 8; ++} ++ + unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples) + { + uint8_t *buffer = samples->pkt->data[0]; +@@ -816,14 +822,22 @@ unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples) + case NEED_BYTESWAP: + Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels); + break; ++ case NEED_RSHIFT8: ++ RShift8_32_buf((uint32_t *)buffer, (uint32_t *)buffer, frames * samples->pkt->config.channels); ++ break; + case CHECK_CONVERT: + ConvertInit(samples); + if (m_convertState == NEED_CONVERT) + buffer = Convert(samples); + else if (m_convertState == NEED_BYTESWAP) + Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels); ++ else if (m_convertState == NEED_RSHIFT8) ++ RShift8_32_buf((uint32_t *)buffer, (uint32_t *)buffer, frames * samples->pkt->config.channels); ++ else if (m_convertState == SKIP_OUTPUT) ++ frames = 0; + break; +- default: ++ case SKIP_OUTPUT: ++ frames = 0; + break; + } + +@@ -862,15 +876,38 @@ unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples) + + void CActiveAESink::ConvertInit(CSampleBuffer* samples) + { +- if (CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample) != m_sinkFormat.m_dataFormat) ++ AEDataFormat srcFmt = CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample); ++ ++ if (srcFmt != m_sinkFormat.m_dataFormat) + { +- m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat); +- if (m_convertBuffer) +- _aligned_free(m_convertBuffer); +- m_convertBufferSampleSize = samples->pkt->max_nb_samples; +- m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16); +- memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize); +- m_convertState = NEED_CONVERT; ++ switch (srcFmt) ++ { ++ case AE_FMT_FLOAT: ++ case AE_FMT_FLOATP: ++ m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat); ++ if (m_convertBuffer) ++ _aligned_free(m_convertBuffer); ++ m_convertBufferSampleSize = samples->pkt->max_nb_samples; ++ m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16); ++ memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize); ++ m_convertState = NEED_CONVERT; ++ break; ++ case AE_FMT_S24NE4H: ++ m_convertState = (m_sinkFormat.m_dataFormat == AE_FMT_S24NE4L) ? NEED_RSHIFT8 : SKIP_OUTPUT; ++ break; ++ case AE_FMT_S24NE4HP: ++ m_convertState = (m_sinkFormat.m_dataFormat == AE_FMT_S24NE4LP) ? NEED_RSHIFT8 : SKIP_OUTPUT; ++ break; ++ default: ++ m_convertState = SKIP_OUTPUT; ++ break; ++ } ++ ++ if (m_convertState == SKIP_OUTPUT) ++ { ++ CLog::Log(LOGERROR, "CActiveAESink::ConvertInit - cannot convert from %s to %s", ++ CAEUtil::DataFormatToStr(srcFmt), CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat)); ++ } + } + else if (AE_IS_RAW(m_requestedFormat.m_dataFormat) && CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat)) + { +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h +index 81b1117..68d7454 100644 +--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h +@@ -139,6 +139,8 @@ class CActiveAESink : private CThread + NEED_CONVERT, + NEED_BYTESWAP, + SKIP_CONVERT, ++ NEED_RSHIFT8, ++ SKIP_OUTPUT + } m_convertState; + + std::string m_deviceFriendlyName; +-- +1.9.3 + diff --git a/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support.patch b/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support.patch deleted file mode 100644 index 0bec4d85f4..0000000000 --- a/projects/Cuboxi/patches/xbmc-master/xbmc-001-imx6_support.patch +++ /dev/null @@ -1,3548 +0,0 @@ -diff -Naur xbmc-13b4/configure.in xbmc-imx6-13b4/configure.in ---- xbmc-13b4/configure.in 2014-04-24 11:49:30.784354037 +0200 -+++ xbmc-imx6-13b4/configure.in 2014-04-24 11:50:13.695216693 +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-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp 2014-04-24 11:49:41.288075640 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -279,14 +279,16 @@ - if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8; - else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; - else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; -- else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32; -+ else if (format == AE_FMT_S24NE4H) return AV_SAMPLE_FMT_S32; -+ else if (format == AE_FMT_S24NE4L) return AV_SAMPLE_FMT_S32; - else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; - else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; - - else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P; - else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; - else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; -- else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P; -+ else if (format == AE_FMT_S24NE4HP) return AV_SAMPLE_FMT_S32P; -+ else if (format == AE_FMT_S24NE4LP) return AV_SAMPLE_FMT_S32P; - else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; - else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; - -@@ -298,14 +300,14 @@ - if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8; - else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE; - else if (format == AV_SAMPLE_FMT_S32 && bits == 32) return AE_FMT_S32NE; -- else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4; -+ else if (format == AV_SAMPLE_FMT_S32 && bits == 24) return AE_FMT_S24NE4H; - else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT; - else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE; - - else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P; - else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP; - else if (format == AV_SAMPLE_FMT_S32P && bits == 32) return AE_FMT_S32NEP; -- else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4P; -+ else if (format == AV_SAMPLE_FMT_S32P && bits == 24) return AE_FMT_S24NE4HP; - else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP; - else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP; - -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp 2014-04-24 11:49:41.280075852 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -796,6 +796,12 @@ - } - } - -+static inline void RShift8_32_buf(uint32_t *src, uint32_t *dst, uint32_t count) -+{ -+ while (count--) -+ *dst++ = *src++ >> 8; -+} -+ - unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples) - { - uint8_t *buffer = samples->pkt->data[0]; -@@ -816,14 +822,22 @@ - case NEED_BYTESWAP: - Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels); - break; -+ case NEED_RSHIFT8: -+ RShift8_32_buf((uint32_t *)buffer, (uint32_t *)buffer, frames * samples->pkt->config.channels); -+ break; - case CHECK_CONVERT: - ConvertInit(samples); - if (m_convertState == NEED_CONVERT) - buffer = Convert(samples); - else if (m_convertState == NEED_BYTESWAP) - Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels); -+ else if (m_convertState == NEED_RSHIFT8) -+ RShift8_32_buf((uint32_t *)buffer, (uint32_t *)buffer, frames * samples->pkt->config.channels); -+ else if (m_convertState == SKIP_OUTPUT) -+ frames = 0; - break; -- default: -+ case SKIP_OUTPUT: -+ frames = 0; - break; - } - -@@ -862,15 +876,38 @@ - - void CActiveAESink::ConvertInit(CSampleBuffer* samples) - { -- if (CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample) != m_sinkFormat.m_dataFormat) -+ AEDataFormat srcFmt = CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt, samples->pkt->config.bits_per_sample); -+ -+ if (srcFmt != m_sinkFormat.m_dataFormat) - { -- m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat); -- if (m_convertBuffer) -- _aligned_free(m_convertBuffer); -- m_convertBufferSampleSize = samples->pkt->max_nb_samples; -- m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16); -- memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize); -- m_convertState = NEED_CONVERT; -+ switch (srcFmt) -+ { -+ case AE_FMT_FLOAT: -+ case AE_FMT_FLOATP: -+ m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat); -+ if (m_convertBuffer) -+ _aligned_free(m_convertBuffer); -+ m_convertBufferSampleSize = samples->pkt->max_nb_samples; -+ m_convertBuffer = (uint8_t*)_aligned_malloc(samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16); -+ memset(m_convertBuffer, 0, samples->pkt->max_nb_samples * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize); -+ m_convertState = NEED_CONVERT; -+ break; -+ case AE_FMT_S24NE4H: -+ m_convertState = (m_sinkFormat.m_dataFormat == AE_FMT_S24NE4L) ? NEED_RSHIFT8 : SKIP_OUTPUT; -+ break; -+ case AE_FMT_S24NE4HP: -+ m_convertState = (m_sinkFormat.m_dataFormat == AE_FMT_S24NE4LP) ? NEED_RSHIFT8 : SKIP_OUTPUT; -+ break; -+ default: -+ m_convertState = SKIP_OUTPUT; -+ break; -+ } -+ -+ if (m_convertState == SKIP_OUTPUT) -+ { -+ CLog::Log(LOGERROR, "CActiveAESink::ConvertInit - cannot convert from %s to %s", -+ CAEUtil::DataFormatToStr(srcFmt), CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat)); -+ } - } - else if (AE_IS_RAW(m_requestedFormat.m_dataFormat) && CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat)) - { -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h ---- xbmc-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h 2014-04-24 11:49:41.288075640 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h 2014-04-24 11:50:14.007208425 +0200 -@@ -139,6 +139,8 @@ - NEED_CONVERT, - NEED_BYTESWAP, - SKIP_CONVERT, -+ NEED_RSHIFT8, -+ SKIP_OUTPUT - } m_convertState; - - std::string m_deviceFriendlyName; -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp 2014-04-24 11:49:41.256076488 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -268,7 +268,7 @@ - case AE_FMT_S16NE : return SND_PCM_FORMAT_S16; - case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE; - case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE; -- case AE_FMT_S24NE4: return SND_PCM_FORMAT_S24; -+ case AE_FMT_S24NE4L: return SND_PCM_FORMAT_S24; - #ifdef __BIG_ENDIAN__ - case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE; - #else -@@ -343,7 +343,7 @@ - { - /* if we opened in 32bit and only have 24bits, pack into 24 */ - if (fmtBits == 32 && bits == 24) -- i = AE_FMT_S24NE4; -+ i = AE_FMT_S24NE4L; - else - continue; - } -@@ -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-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp 2014-04-24 11:49:41.268076170 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkPULSE.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -80,9 +80,9 @@ - case AE_FMT_S24LE3: return PA_SAMPLE_S24LE; - case AE_FMT_S24BE3: return PA_SAMPLE_S24BE; - case AE_FMT_S24NE3: return PA_SAMPLE_S24NE; -- case AE_FMT_S24LE4: return PA_SAMPLE_S24_32LE; -- case AE_FMT_S24BE4: return PA_SAMPLE_S24_32BE; -- case AE_FMT_S24NE4: return PA_SAMPLE_S24_32NE; -+ case AE_FMT_S24LE4L: return PA_SAMPLE_S24_32LE; -+ case AE_FMT_S24BE4L: return PA_SAMPLE_S24_32BE; -+ case AE_FMT_S24NE4L: return PA_SAMPLE_S24_32NE; - case AE_FMT_S32BE : return PA_SAMPLE_S32BE; - case AE_FMT_S32LE : return PA_SAMPLE_S32LE; - case AE_FMT_S32NE : return PA_SAMPLE_S32NE; -@@ -119,9 +119,9 @@ - AE_FMT_S24LE3, - AE_FMT_S24BE3, - AE_FMT_S24NE3, -- AE_FMT_S24LE4, -- AE_FMT_S24BE4, -- AE_FMT_S24NE4, -+ AE_FMT_S24LE4L, -+ AE_FMT_S24BE4L, -+ AE_FMT_S24NE4L, - AE_FMT_S32BE, - AE_FMT_S32LE, - AE_FMT_S32NE, -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp 2014-04-24 11:49:41.276075958 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -111,7 +111,7 @@ - /* Sample formats go from float -> 32 bit int -> 24 bit int (packed in 32) -> -> 24 bit int -> 16 bit int */ - static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, AE_FMT_FLOAT}, - {KSDATAFORMAT_SUBTYPE_PCM, 32, 32, AE_FMT_S32NE}, -- {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4}, -+ {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4H}, - {KSDATAFORMAT_SUBTYPE_PCM, 24, 24, AE_FMT_S24NE3}, - {KSDATAFORMAT_SUBTYPE_PCM, 16, 16, AE_FMT_S16NE} }; - -@@ -758,7 +758,7 @@ - wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p); - wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3); - wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign; -- if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4) -+ if (p <= AE_FMT_S24NE4H && p >= AE_FMT_S24BE4H) - { - wfxex.Samples.wValidBitsPerSample = 24; - } -@@ -1149,7 +1149,7 @@ - else if (wfxex.Samples.wValidBitsPerSample == 32) - format.m_dataFormat = AE_FMT_S32NE; - else -- format.m_dataFormat = AE_FMT_S24NE4; -+ format.m_dataFormat = AE_FMT_S24NE4H; - } - else if (wfxex.Format.wBitsPerSample == 24) - format.m_dataFormat = AE_FMT_S24NE3; -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h ---- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h 2014-04-24 11:49:41.296075428 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEAudioFormat.h 2014-04-24 11:50:14.011208319 +0200 -@@ -41,9 +41,13 @@ - AE_FMT_S32LE, - AE_FMT_S32NE, - -- AE_FMT_S24BE4, -- AE_FMT_S24LE4, -- AE_FMT_S24NE4, /* S24 in 4 bytes */ -+ AE_FMT_S24BE4H, -+ AE_FMT_S24LE4H, -+ AE_FMT_S24NE4H, /* S24 in upper 4 bytes */ -+ -+ AE_FMT_S24BE4L, -+ AE_FMT_S24LE4L, -+ AE_FMT_S24NE4L, /* S24 in lower 4 bytes */ - - AE_FMT_S24BE3, - AE_FMT_S24LE3, -@@ -65,7 +69,8 @@ - AE_FMT_U8P, - AE_FMT_S16NEP, - AE_FMT_S32NEP, -- AE_FMT_S24NE4P, -+ AE_FMT_S24NE4HP, -+ AE_FMT_S24NE4LP, - AE_FMT_S24NE3P, - AE_FMT_DOUBLEP, - AE_FMT_FLOATP, -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp 2014-04-24 11:49:41.292075533 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -69,18 +69,22 @@ - #ifdef __BIG_ENDIAN__ - case AE_FMT_S16NE : return &S16BE_Float; - case AE_FMT_S32NE : return &S32BE_Float; -- case AE_FMT_S24NE4: return &S24BE4_Float; -+ case AE_FMT_S24NE4H: return &S24BE4H_Float; -+ case AE_FMT_S24NE4L: return &S24BE4L_Float; - case AE_FMT_S24NE3: return &S24BE3_Float; - #else - case AE_FMT_S16NE : return &S16LE_Float; - case AE_FMT_S32NE : return &S32LE_Float; -- case AE_FMT_S24NE4: return &S24LE4_Float; -+ case AE_FMT_S24NE4H: return &S24LE4H_Float; -+ case AE_FMT_S24NE4L: return &S24LE4L_Float; - case AE_FMT_S24NE3: return &S24LE3_Float; - #endif - case AE_FMT_S16LE : return &S16LE_Float; - case AE_FMT_S16BE : return &S16BE_Float; -- case AE_FMT_S24LE4: return &S24LE4_Float; -- case AE_FMT_S24BE4: return &S24BE4_Float; -+ case AE_FMT_S24LE4H: return &S24LE4H_Float; -+ case AE_FMT_S24LE4L: return &S24LE4L_Float; -+ case AE_FMT_S24BE4H: return &S24BE4H_Float; -+ case AE_FMT_S24BE4L: return &S24BE4L_Float; - case AE_FMT_S24LE3: return &S24LE3_Float; - case AE_FMT_S24BE3: return &S24BE3_Float; - #if defined(__ARM_NEON__) -@@ -112,7 +116,8 @@ - #endif - case AE_FMT_S16LE : return &Float_S16LE; - case AE_FMT_S16BE : return &Float_S16BE; -- case AE_FMT_S24NE4: return &Float_S24NE4; -+ case AE_FMT_S24NE4H: return &Float_S24NE4H; -+ case AE_FMT_S24NE4L: return &Float_S24NE4L; - case AE_FMT_S24NE3: return &Float_S24NE3; - #if defined(__ARM_NEON__) - case AE_FMT_S32LE : return &Float_S32LE_Neon; -@@ -210,7 +215,17 @@ - return samples; - } - --unsigned int CAEConvert::S24LE4_Float(uint8_t *data, const unsigned int samples, float *dest) -+unsigned int CAEConvert::S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest) -+{ -+ for (unsigned int i = 0; i < samples; ++i, data += 4) -+ { -+ int s = (data[3] << 24) | (data[2] << 16) | (data[1] << 8); -+ *dest++ = (float)s * INT32_SCALE; -+ } -+ return samples; -+} -+ -+unsigned int CAEConvert::S24LE4L_Float(uint8_t *data, const unsigned int samples, float *dest) - { - for (unsigned int i = 0; i < samples; ++i, data += 4) - { -@@ -220,7 +235,7 @@ - return samples; - } - --unsigned int CAEConvert::S24BE4_Float(uint8_t *data, const unsigned int samples, float *dest) -+unsigned int CAEConvert::S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest) - { - for (unsigned int i = 0; i < samples; ++i, data += 4) - { -@@ -230,6 +245,16 @@ - return samples; - } - -+unsigned int CAEConvert::S24BE4L_Float(uint8_t *data, const unsigned int samples, float *dest) -+{ -+ for (unsigned int i = 0; i < samples; ++i, data += 4) -+ { -+ int s = (data[1] << 24) | (data[2] << 16) | (data[3] << 8); -+ *dest++ = (float)s * INT32_SCALE; -+ } -+ return samples; -+} -+ - unsigned int CAEConvert::S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest) - { - for (unsigned int i = 0; i < samples; ++i, data += 3) -@@ -244,7 +269,7 @@ - { - for (unsigned int i = 0; i < samples; ++i, data += 3) - { -- int s = (data[1] << 24) | (data[2] << 16) | (data[3] << 8); -+ int s = (data[0] << 24) | (data[1] << 16) | (data[2] << 8); - *dest++ = (float)s * INT32_SCALE; - } - return samples; -@@ -786,7 +811,7 @@ - return samples << 1; - } - --unsigned int CAEConvert::Float_S24NE4(float *data, const unsigned int samples, uint8_t *dest) -+unsigned int CAEConvert::Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest) - { - int32_t *dst = (int32_t*)dest; - #ifdef __SSE2__ -@@ -797,7 +822,7 @@ - /* work around invalid alignment */ - while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) - { -- dst[0] = (safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8; -+ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) << 8; - ++data; - ++dst; - --count; -@@ -816,7 +841,7 @@ - { - const uint32_t odd = count - even; - if (odd == 1) -- dst[0] = (safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF) << 8; -+ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) << 8; - else - { - __m128 in; -@@ -841,7 +866,69 @@ - _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)) << 8; -+ #endif -+ -+ return samples << 2; -+} -+ -+unsigned int CAEConvert::Float_S24NE4L(float *data, const unsigned int samples, uint8_t *dest) -+{ -+ int32_t *dst = (int32_t*)dest; -+ #ifdef __SSE2__ -+ -+ const __m128i msk = _mm_set1_epi32(0xFFFFFF); -+ const __m128 mul = _mm_set_ps1((float)INT24_MAX+.5f); -+ unsigned int count = samples; -+ -+ /* work around invalid alignment */ -+ while ((((uintptr_t)data & 0xF) || ((uintptr_t)dest & 0xF)) && count > 0) -+ { -+ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF; -+ ++data; -+ ++dst; -+ --count; -+ } -+ -+ const uint32_t even = count & ~0x3; -+ for (uint32_t i = 0; i < even; i += 4, data += 4, dst += 4) -+ { -+ __m128 in = _mm_mul_ps(_mm_load_ps(data), mul); -+ __m128i con = _mm_cvtps_epi32(in); -+ con = _mm_and_si128(con, msk); -+ memcpy(dst, &con, sizeof(int32_t) * 4); -+ } -+ -+ if (count != even) -+ { -+ const uint32_t odd = count - even; -+ if (odd == 1) -+ dst[0] = safeRound(data[0] * ((float)INT24_MAX+.5f)) & 0xFFFFFF; -+ else -+ { -+ __m128 in; -+ if (odd == 2) -+ { -+ in = _mm_setr_ps(data[0], data[1], 0, 0); -+ in = _mm_mul_ps(in, mul); -+ __m128i con = _mm_cvtps_epi32(in); -+ con = _mm_and_si128(con, msk); -+ memcpy(dst, &con, sizeof(int32_t) * 2); -+ } -+ else -+ { -+ in = _mm_setr_ps(data[0], data[1], data[2], 0); -+ in = _mm_mul_ps(in, mul); -+ __m128i con = _mm_cvtps_epi32(in); -+ con = _mm_and_si128(con, msk); -+ memcpy(dst, &con, sizeof(int32_t) * 3); -+ } -+ } -+ } -+ _mm_empty(); -+ #else /* no SSE2 */ -+ for (uint32_t i = 0; i < samples; ++i) -+ *dst++ = safeRound(*data++ * ((float)INT24_MAX+.5f)) & 0xFFFFFF; - #endif - - return samples << 2; -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h ---- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h 2014-04-24 11:49:41.292075533 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEConvert.h 2014-04-24 11:50:14.007208425 +0200 -@@ -28,8 +28,10 @@ - static unsigned int S8_Float (uint8_t *data, const unsigned int samples, float *dest); - static unsigned int S16LE_Float (uint8_t *data, const unsigned int samples, float *dest); - static unsigned int S16BE_Float (uint8_t *data, const unsigned int samples, float *dest); -- static unsigned int S24LE4_Float(uint8_t *data, const unsigned int samples, float *dest); -- static unsigned int S24BE4_Float(uint8_t *data, const unsigned int samples, float *dest); -+ static unsigned int S24LE4H_Float(uint8_t *data, const unsigned int samples, float *dest); -+ static unsigned int S24LE4L_Float(uint8_t *data, const unsigned int samples, float *dest); -+ static unsigned int S24BE4H_Float(uint8_t *data, const unsigned int samples, float *dest); -+ static unsigned int S24BE4L_Float(uint8_t *data, const unsigned int samples, float *dest); - static unsigned int S24LE3_Float(uint8_t *data, const unsigned int samples, float *dest); - static unsigned int S24BE3_Float(uint8_t *data, const unsigned int samples, float *dest); - static unsigned int S32LE_Float (uint8_t *data, const unsigned int samples, float *dest); -@@ -41,7 +43,8 @@ - static unsigned int Float_S8 (float *data, const unsigned int samples, uint8_t *dest); - static unsigned int Float_S16LE (float *data, const unsigned int samples, uint8_t *dest); - static unsigned int Float_S16BE (float *data, const unsigned int samples, uint8_t *dest); -- static unsigned int Float_S24NE4(float *data, const unsigned int samples, uint8_t *dest); -+ static unsigned int Float_S24NE4H(float *data, const unsigned int samples, uint8_t *dest); -+ static unsigned int Float_S24NE4L(float *data, const unsigned int samples, uint8_t *dest); - static unsigned int Float_S24NE3(float *data, const unsigned int samples, uint8_t *dest); - static unsigned int Float_S32LE (float *data, const unsigned int samples, uint8_t *dest); - static unsigned int Float_S32BE (float *data, const unsigned int samples, uint8_t *dest); -diff -Naur xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ---- xbmc-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp 2014-04-24 11:49:41.296075428 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/AudioEngine/Utils/AEUtil.cpp 2014-04-24 11:50:14.007208425 +0200 -@@ -92,9 +92,13 @@ - 32, /* S32LE */ - 32, /* S32NE */ - -- 32, /* S24BE */ -- 32, /* S24LE */ -- 32, /* S24NE */ -+ 32, /* S24BE4H */ -+ 32, /* S24LE4H */ -+ 32, /* S24NE4H */ -+ -+ 32, /* S24BE4L */ -+ 32, /* S24LE4L */ -+ 32, /* S24NE4L */ - - 24, /* S24BE3 */ - 24, /* S24LE3 */ -@@ -114,8 +118,9 @@ - 8, /* U8P */ - 16, /* S16NEP */ - 32, /* S32NEP */ -- 32, /* S24NEP */ -- 24, /* S24NE3P*/ -+ 32, /* S24NE4HP */ -+ 32, /* S24NE4LP */ -+ 24, /* S24NE3P */ - sizeof(double) << 3, /* DOUBLEP */ - sizeof(float ) << 3 /* FLOATP */ - }; -@@ -125,7 +130,8 @@ - - const unsigned int CAEUtil::DataFormatToUsedBits(const enum AEDataFormat dataFormat) - { -- if (dataFormat == AE_FMT_S24BE4 || dataFormat == AE_FMT_S24LE4 || dataFormat == AE_FMT_S24NE4) -+ if (dataFormat == AE_FMT_S24BE4H || dataFormat == AE_FMT_S24LE4H || dataFormat == AE_FMT_S24NE4H || -+ dataFormat == AE_FMT_S24BE4L || dataFormat == AE_FMT_S24LE4L || dataFormat == AE_FMT_S24NE4L) - return 24; - else - return DataFormatToBits(dataFormat); -@@ -149,9 +155,13 @@ - "AE_FMT_S32LE", - "AE_FMT_S32NE", - -- "AE_FMT_S24BE4", -- "AE_FMT_S24LE4", -- "AE_FMT_S24NE4", /* S24 in 4 bytes */ -+ "AE_FMT_S24BE4H", -+ "AE_FMT_S24LE4H", -+ "AE_FMT_S24NE4H", /* S24 in upper 4 bytes */ -+ -+ "AE_FMT_S24BE4L", -+ "AE_FMT_S24LE4L", -+ "AE_FMT_S24NE4L", /* S24 in lower 4 bytes */ - - "AE_FMT_S24BE3", - "AE_FMT_S24LE3", -@@ -173,7 +183,8 @@ - "AE_FMT_U8P", - "AE_FMT_S16NEP", - "AE_FMT_S32NEP", -- "AE_FMT_S24NE4P", -+ "AE_FMT_S24NE4HP", -+ "AE_FMT_S24NE4LP", - "AE_FMT_S24NE3P", - "AE_FMT_DOUBLEP", - "AE_FMT_FLOATP" -diff -Naur xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp 2014-04-24 11:49:41.204077867 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp 2014-04-24 11:50:14.007208425 +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-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2014-04-24 11:49:41.200077973 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h 2014-04-24 11:50:14.007208425 +0200 -@@ -27,6 +27,7 @@ - #include - #include - #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-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.cpp 2014-04-24 11:50:14.007208425 +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 -+ * . -+ * -+ */ -+ -+#include "DVDVideoCodecIMX.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#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; inSubBlockNum; 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; i1) -+ { -+ 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; iOpen(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; iReleaseFramebuffer(&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-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecIMX.h 2014-04-24 11:50:14.007208425 +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 -+ * . -+ * -+ */ -+#include -+#include -+#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-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecInfo.h 2014-04-24 11:50:14.007208425 +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 -+ * . -+ * -+ */ -+ -+#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-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2014-04-24 11:49:41.192078185 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in 2014-04-24 11:50:14.007208425 +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-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp ---- xbmc-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2014-04-24 11:49:41.128079881 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp 2014-04-24 11:50:14.003208531 +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-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp ---- xbmc-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp 2014-04-24 11:49:41.300075322 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp 2014-04-24 11:50:14.011208319 +0200 -@@ -75,6 +75,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 -@@ -99,6 +110,7 @@ - #if defined(TARGET_ANDROID) - mediacodec = NULL; - #endif -+ codecinfo = NULL; - } - - CLinuxRendererGLES::YUVBUFFER::~YUVBUFFER() -@@ -150,6 +162,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() -@@ -278,6 +296,10 @@ - { - return source; - } -+ if ( m_renderMethod & RENDER_IMXMAP ) -+ { -+ return source; -+ } - - #ifdef HAVE_VIDEOTOOLBOXDECODER - if (m_renderMethod & RENDER_CVREF ) -@@ -603,6 +625,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; -@@ -713,6 +739,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"); -@@ -805,6 +841,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 -@@ -956,6 +1004,10 @@ - { - RenderSurfaceTexture(index, m_currentField); - } -+ else if (m_renderMethod & RENDER_IMXMAP) -+ { -+ RenderIMXMAPTexture(index, m_currentField); -+ } - else - { - RenderSoftware(index, m_currentField); -@@ -1160,7 +1212,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); -@@ -1582,6 +1634,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) -@@ -2303,7 +2434,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); -@@ -2409,7 +2540,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); - -@@ -2483,6 +2614,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 ; iIsValid()) -+ { -+ 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 -@@ -2578,9 +2895,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; - } -@@ -2609,6 +2931,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 -@@ -2657,6 +2988,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 -@@ -2741,5 +3075,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-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h ---- xbmc-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h 2014-04-24 11:49:41.304075216 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/LinuxRendererGLES.h 2014-04-24 11:50:14.011208319 +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-13b4/xbmc/cores/VideoRenderers/RenderFormats.h xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderFormats.h ---- xbmc-13b4/xbmc/cores/VideoRenderers/RenderFormats.h 2014-04-24 11:49:41.300075322 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderFormats.h 2014-04-24 11:50:14.011208319 +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-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp ---- xbmc-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp 2014-04-24 11:49:41.308075110 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/RenderManager.cpp 2014-04-24 11:50:14.011208319 +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-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp xbmc-imx6-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp ---- xbmc-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2014-04-24 11:49:41.304075216 +0200 -+++ xbmc-imx6-13b4/xbmc/cores/VideoRenderers/VideoShaders/YUV2RGBShader.cpp 2014-04-24 11:50:14.011208319 +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-13b4/xbmc/input/linux/LinuxInputDevices.cpp xbmc-imx6-13b4/xbmc/input/linux/LinuxInputDevices.cpp -diff -Naur xbmc-13b4/xbmc/powermanagement/PowerManager.cpp xbmc-imx6-13b4/xbmc/powermanagement/PowerManager.cpp -diff -Naur xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp ---- xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.cpp 2014-04-24 11:50:14.019208107 +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 -+ * . -+ * -+ */ -+ -+#include -+#include "system.h" -+#include -+ -+#include "EGLNativeTypeIMX.h" -+#include -+#include -+#include -+#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 -+ -+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 &resolutions) -+{ -+ if (m_readonly) -+ return false; -+ -+ std::string valstr; -+ get_sysfs_str("/sys/class/graphics/fb0/modes", valstr); -+ std::vector 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-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h ---- xbmc-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h 1970-01-01 01:00:00.000000000 +0100 -+++ xbmc-imx6-13b4/xbmc/windowing/egl/EGLNativeTypeIMX.h 2014-04-24 11:50:14.019208107 +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 -+ * . -+ * -+ */ -+#include -+#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 &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-13b4/xbmc/windowing/egl/EGLWrapper.cpp xbmc-imx6-13b4/xbmc/windowing/egl/EGLWrapper.cpp ---- xbmc-13b4/xbmc/windowing/egl/EGLWrapper.cpp 2014-04-24 11:49:41.748063448 +0200 -+++ xbmc-imx6-13b4/xbmc/windowing/egl/EGLWrapper.cpp 2014-04-24 11:50:14.019208107 +0200 -@@ -17,16 +17,17 @@ - * . - * - */ -- - #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(implementation)) || - (nativeGuess = CreateEGLNativeType(implementation)) || - (nativeGuess = CreateEGLNativeType(implementation)) || -- (nativeGuess = CreateEGLNativeType(implementation))) -+ (nativeGuess = CreateEGLNativeType(implementation)) -+#ifdef HAS_IMXFB -+ || (nativeGuess = CreateEGLNativeType(implementation)) -+#endif -+ ) - { - m_nativeTypes = nativeGuess; - -diff -Naur xbmc-13b4/xbmc/windowing/egl/Makefile.in xbmc-imx6-13b4/xbmc/windowing/egl/Makefile.in ---- xbmc-13b4/xbmc/windowing/egl/Makefile.in 2014-04-24 11:49:41.736063766 +0200 -+++ xbmc-imx6-13b4/xbmc/windowing/egl/Makefile.in 2014-04-24 11:50:14.019208107 +0200 -@@ -24,6 +24,10 @@ - wayland/XBMCSurface.cpp - endif - -+ifeq (@USE_IMXFB@,1) -+SRCS+= EGLNativeTypeIMX.cpp -+endif -+ - LIB = windowing_egl.a - - include ../../../Makefile.include