Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[rbp] adadded raspberrypi openmax support

  • Loading branch information...
commit 5dda4e6fce82845d30cca94bb8e0da035801012c 1 parent af49207
@huceke authored
View
123 xbmc/linux/DllOMX.h
@@ -0,0 +1,123 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2010 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, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#if defined(HAVE_OMXLIB)
+
+#if (defined HAVE_CONFIG_H) && (!defined WIN32)
+ #include "config.h"
+#endif
+#ifndef __GNUC__
+#pragma warning(push)
+#pragma warning(disable:4244)
+#endif
+
+#include "DynamicDll.h"
+#include "utils/log.h"
+
+#include <IL/OMX_Core.h>
+#include <IL/OMX_Component.h>
+#include <IL/OMX_Index.h>
+#include <IL/OMX_Image.h>
+#include <IL/OMX_Video.h>
+#include <IL/OMX_Broadcom.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+class DllOMXInterface
+{
+public:
+ virtual ~DllOMXInterface() {}
+
+ virtual OMX_ERRORTYPE OMX_Init(void) = 0;
+ virtual OMX_ERRORTYPE OMX_Deinit(void) = 0;
+ virtual OMX_ERRORTYPE OMX_GetHandle(OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks) = 0;
+ virtual OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE hComponent) = 0;
+ virtual OMX_ERRORTYPE OMX_GetComponentsOfRole(OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames) = 0;
+ virtual OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles) = 0;
+ virtual OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex) = 0;
+ virtual OMX_ERRORTYPE OMX_SetupTunnel(OMX_HANDLETYPE hOutput, OMX_U32 nPortOutput, OMX_HANDLETYPE hInput, OMX_U32 nPortInput) = 0;
+
+};
+
+#if (defined USE_EXTERNAL_OMX)
+class DllOMX : public DllDynamic, DllOMXInterface
+{
+public:
+ virtual OMX_ERRORTYPE OMX_Init(void)
+ { return ::OMX_Init(); };
+ virtual OMX_ERRORTYPE OMX_Deinit(void)
+ { return ::OMX_Deinit(); };
+ virtual OMX_ERRORTYPE OMX_GetHandle(OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks)
+ { return ::OMX_GetHandle(pHandle, cComponentName, pAppData, pCallBacks); };
+ virtual OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE hComponent)
+ { return ::OMX_FreeHandle(hComponent); };
+ virtual OMX_ERRORTYPE OMX_GetComponentsOfRole(OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames)
+ { return ::OMX_GetComponentsOfRole(role, pNumComps, compNames); };
+ virtual OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles)
+ { return ::OMX_GetRolesOfComponent(compName, pNumRoles, roles); };
+ virtual OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex)
+ { return ::OMX_ComponentNameEnum(cComponentName, nNameLength, nIndex); };
+ virtual OMX_ERRORTYPE OMX_SetupTunnel(OMX_HANDLETYPE hOutput, OMX_U32 nPortOutput, OMX_HANDLETYPE hInput, OMX_U32 nPortInput)
+ { return ::OMX_SetupTunnel(hOutput, nPortOutput, hInput, nPortInput); };
+ virtual bool ResolveExports()
+ { return true; }
+ virtual bool Load()
+ {
+ CLog::Log(LOGDEBUG, "DllOMX: Using omx system library");
+ return true;
+ }
+ virtual void Unload() {}
+};
+#else
+class DllOMX : public DllDynamic, DllOMXInterface
+{
+ //DECLARE_DLL_WRAPPER(DllLibOpenMax, "/usr/lib/libnvomx.so")
+ DECLARE_DLL_WRAPPER(DllOMX, "/opt/vc/lib/libopenmaxil.so")
+
+ DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Init)
+ DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Deinit)
+ DEFINE_METHOD4(OMX_ERRORTYPE, OMX_GetHandle, (OMX_HANDLETYPE *p1, OMX_STRING p2, OMX_PTR p3, OMX_CALLBACKTYPE *p4))
+ DEFINE_METHOD1(OMX_ERRORTYPE, OMX_FreeHandle, (OMX_HANDLETYPE p1))
+ DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetComponentsOfRole, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
+ DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetRolesOfComponent, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
+ DEFINE_METHOD3(OMX_ERRORTYPE, OMX_ComponentNameEnum, (OMX_STRING p1, OMX_U32 p2, OMX_U32 p3))
+ DEFINE_METHOD4(OMX_ERRORTYPE, OMX_SetupTunnel, (OMX_HANDLETYPE p1, OMX_U32 p2, OMX_HANDLETYPE p3, OMX_U32 p4));
+ BEGIN_METHOD_RESOLVE()
+ RESOLVE_METHOD(OMX_Init)
+ RESOLVE_METHOD(OMX_Deinit)
+ RESOLVE_METHOD(OMX_GetHandle)
+ RESOLVE_METHOD(OMX_FreeHandle)
+ RESOLVE_METHOD(OMX_GetComponentsOfRole)
+ RESOLVE_METHOD(OMX_GetRolesOfComponent)
+ RESOLVE_METHOD(OMX_ComponentNameEnum)
+ RESOLVE_METHOD(OMX_SetupTunnel)
+ END_METHOD_RESOLVE()
+
+public:
+ virtual bool Load()
+ {
+ return DllDynamic::Load();
+ }
+};
+#endif
+
+#endif
View
3  xbmc/linux/Makefile.in
@@ -15,6 +15,9 @@ SRCS=ConvUtils.cpp \
XLCDproc.cpp \
XMemUtils.cpp \
XTimeUtils.cpp \
+ RBP.cpp \
+ OMXClock.cpp \
+ OMXCore.cpp \
ifeq (@USE_ANDROID@,1)
SRCS+=getdelim.c
View
1,061 xbmc/linux/OMXClock.cpp
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (C) 2005-2008 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, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#if (defined HAVE_CONFIG_H) && (!defined WIN32)
+ #include "config.h"
+#elif defined(_WIN32)
+#include "system.h"
+#endif
+
+#include "video/VideoReferenceClock.h"
+#include "settings/GUISettings.h"
+
+#include "OMXClock.h"
+#include "utils/MathUtils.h"
+
+int64_t OMXClock::m_systemOffset;
+int64_t OMXClock::m_systemFrequency;
+bool OMXClock::m_ismasterclock;
+
+OMXClock::OMXClock()
+{
+ m_has_video = false;
+ m_has_audio = false;
+ m_video_start = false;
+ m_audio_start = false;
+ m_pause = false;
+
+ m_systemOffset = 0;
+ m_systemFrequency = 0;
+
+ CheckSystemClock();
+
+ m_systemUsed = m_systemFrequency;
+ m_pauseClock = 0;
+ m_bReset = true;
+ m_iDisc = 0;
+ m_maxspeedadjust = 0.0;
+ m_speedadjust = false;
+ m_ismasterclock = true;
+ m_ClockOffset = 0;
+ m_fps = 25.0f;
+ m_omx_speed = DVD_PLAYSPEED_NORMAL;
+ m_audio_buffer = false;
+
+ pthread_mutex_init(&m_lock, NULL);
+}
+
+OMXClock::~OMXClock()
+{
+ OMXDeinitialize();
+ pthread_mutex_destroy(&m_lock);
+}
+
+void OMXClock::Lock()
+{
+ pthread_mutex_lock(&m_lock);
+}
+
+void OMXClock::UnLock()
+{
+ pthread_mutex_unlock(&m_lock);
+}
+
+double OMXClock::GetAbsoluteClock(bool interpolated /*= true*/)
+{
+ Lock();
+ CheckSystemClock();
+
+ int64_t current;
+ current = g_VideoReferenceClock.GetTime(interpolated);
+
+ UnLock();
+ return SystemToAbsolute(current);
+}
+
+double OMXClock::WaitAbsoluteClock(double target)
+{
+ Lock();
+ CheckSystemClock();
+
+ int64_t systemtarget, freq, offset;
+ freq = m_systemFrequency;
+ offset = m_systemOffset;
+ UnLock();
+
+ systemtarget = (int64_t)(target / DVD_TIME_BASE * (double)freq);
+ systemtarget += offset;
+ systemtarget = g_VideoReferenceClock.Wait(systemtarget);
+ systemtarget -= offset;
+ return (double)systemtarget / freq * DVD_TIME_BASE;
+}
+
+// Returns the current absolute clock in units of DVD_TIME_BASE (usually microseconds).
+void OMXClock::CheckSystemClock()
+{
+ if(!m_systemFrequency)
+ m_systemFrequency = g_VideoReferenceClock.GetFrequency();
+
+ if(!m_systemOffset)
+ m_systemOffset = g_VideoReferenceClock.GetTime();
+}
+
+double OMXClock::GetClock(bool interpolated /*= true*/)
+{
+ Lock();
+ double clock = SystemToPlaying(g_VideoReferenceClock.GetTime(interpolated));
+ UnLock();
+ return clock;
+}
+
+double OMXClock::GetClock(double& absolute, bool interpolated /*= true*/)
+{
+ int64_t current = g_VideoReferenceClock.GetTime(interpolated);
+
+ Lock();
+ CheckSystemClock();
+ absolute = SystemToAbsolute(current);
+ current = SystemToPlaying(current);
+ UnLock();
+
+ return current;
+}
+
+void OMXClock::SetSpeed(int iSpeed)
+{
+ // this will sometimes be a little bit of due to rounding errors, ie clock might jump abit when changing speed
+ Lock();
+
+ if(iSpeed == DVD_PLAYSPEED_PAUSE)
+ {
+ if(!m_pauseClock)
+ m_pauseClock = g_VideoReferenceClock.GetTime();
+ UnLock();
+ return;
+ }
+
+ int64_t current;
+ int64_t newfreq = m_systemFrequency * DVD_PLAYSPEED_NORMAL / iSpeed;
+
+ current = g_VideoReferenceClock.GetTime();
+ if( m_pauseClock )
+ {
+ m_startClock += current - m_pauseClock;
+ m_pauseClock = 0;
+ }
+
+ m_startClock = current - (int64_t)((double)(current - m_startClock) * newfreq / m_systemUsed);
+ m_systemUsed = newfreq;
+ UnLock();
+}
+
+void OMXClock::Discontinuity(double currentPts)
+{
+ Lock();
+ m_startClock = g_VideoReferenceClock.GetTime();
+ if(m_pauseClock)
+ m_pauseClock = m_startClock;
+ m_iDisc = currentPts;
+ m_bReset = false;
+ UnLock();
+}
+
+void OMXClock::Pause()
+{
+ Lock();
+ if(!m_pauseClock)
+ m_pauseClock = g_VideoReferenceClock.GetTime();
+ UnLock();
+}
+
+void OMXClock::Resume()
+{
+ Lock();
+ if( m_pauseClock )
+ {
+ int64_t current;
+ current = g_VideoReferenceClock.GetTime();
+
+ m_startClock += current - m_pauseClock;
+ m_pauseClock = 0;
+ }
+ UnLock();
+}
+
+bool OMXClock::SetMaxSpeedAdjust(double speed)
+{
+ Lock();
+ m_maxspeedadjust = speed;
+ UnLock();
+ return m_speedadjust;
+}
+
+//returns the refreshrate if the videoreferenceclock is running, -1 otherwise
+int OMXClock::UpdateFramerate(double fps, double* interval /*= NULL*/)
+{
+ //sent with fps of 0 means we are not playing video
+ if(fps == 0.0)
+ {
+ Lock();
+ m_speedadjust = false;
+ UnLock();
+ return -1;
+ }
+
+ //check if the videoreferenceclock is running, will return -1 if not
+ int rate = g_VideoReferenceClock.GetRefreshRate(interval);
+
+ if (rate <= 0)
+ return -1;
+
+ Lock();
+
+ m_speedadjust = true;
+
+ double weight = (double)rate / (double)MathUtils::round_int(fps);
+
+ //set the speed of the videoreferenceclock based on fps, refreshrate and maximum speed adjust set by user
+ if (m_maxspeedadjust > 0.05)
+ {
+ if (weight / MathUtils::round_int(weight) < 1.0 + m_maxspeedadjust / 100.0
+ && weight / MathUtils::round_int(weight) > 1.0 - m_maxspeedadjust / 100.0)
+ weight = MathUtils::round_int(weight);
+ }
+ double speed = (double)rate / (fps * weight);
+ UnLock();
+
+ g_VideoReferenceClock.SetSpeed(speed);
+
+ return rate;
+}
+
+double OMXClock::SystemToAbsolute(int64_t system)
+{
+ return DVD_TIME_BASE * (double)(system - m_systemOffset) / m_systemFrequency;
+}
+
+double OMXClock::SystemToPlaying(int64_t system)
+{
+ int64_t current;
+
+ if (m_bReset)
+ {
+ m_startClock = system;
+ m_systemUsed = m_systemFrequency;
+ m_pauseClock = 0;
+ m_iDisc = 0;
+ m_bReset = false;
+ }
+
+ if (m_pauseClock)
+ current = m_pauseClock;
+ else
+ current = system;
+
+ return DVD_TIME_BASE * (double)(current - m_startClock) / m_systemUsed + m_iDisc;
+}
+
+void OMXClock::OMXSetClockPorts(OMX_TIME_CONFIG_CLOCKSTATETYPE *clock)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return;
+
+ if(!clock)
+ return;
+
+ if(m_has_audio)
+ {
+ m_audio_start = true;
+ clock->nWaitMask |= OMX_CLOCKPORT0;
+ }
+
+ if(m_has_video)
+ {
+ m_video_start = true;
+ clock->nWaitMask |= OMX_CLOCKPORT1;
+ }
+}
+
+bool OMXClock::OMXSetReferenceClock(bool lock /* = true */)
+{
+ if(lock)
+ Lock();
+
+ bool ret = true;
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock;
+ OMX_INIT_STRUCTURE(refClock);
+
+ if(g_guiSettings.GetBool("videoplayer.usedisplayasclock") && m_has_video)
+ refClock.eClock = OMX_TIME_RefClockVideo;
+ else if(m_has_audio)
+ refClock.eClock = OMX_TIME_RefClockAudio;
+ else
+ refClock.eClock = OMX_TIME_RefClockVideo;
+
+ CLog::Log(LOGNOTICE, "OMXClock using %s as reference\n", refClock.eClock == OMX_TIME_RefClockVideo ? "video" : "audio");
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeActiveRefClock, &refClock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::OMXSetReferenceClock error setting OMX_IndexConfigTimeActiveRefClock\n");
+ ret = false;
+ }
+
+ UnLock();
+
+ return ret;
+}
+
+bool OMXClock::OMXInitialize(bool has_video, bool has_audio)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ std::string componentName = "";
+
+ m_has_video = has_video;
+ m_has_audio = has_audio;
+
+ m_video_start = false;
+ m_audio_start = false;
+ m_pause = false;
+ m_audio_buffer = false;
+
+ componentName = "OMX.broadcom.clock";
+ if(!m_omx_clock.Initialize((const std::string)componentName, OMX_IndexParamOtherInit))
+ return false;
+
+ if(!OMXSetReferenceClock(false))
+ return false;
+
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGWARNING, "OMXClock::OMXInitialize setting OMX_IndexConfigTimeClockState\n");
+
+ return true;
+}
+
+void OMXClock::OMXDeinitialize()
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return;
+
+ m_omx_clock.Deinitialize();
+
+ m_omx_speed = DVD_PLAYSPEED_NORMAL;
+}
+
+bool OMXClock::OMXStatePause(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ if(m_omx_clock.GetState() != OMX_StatePause)
+ {
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ omx_err = m_omx_clock.SetStateForComponent(OMX_StatePause);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::StatePause m_omx_clock.SetStateForComponent\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+bool OMXClock::OMXStateExecute(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(m_omx_clock.GetState() != OMX_StateExecuting)
+ {
+
+ OMXStateIdle(false);
+
+ omx_err = m_omx_clock.SetStateForComponent(OMX_StateExecuting);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::StateExecute m_omx_clock.SetStateForComponent\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+ }
+
+ /*
+ if(m_has_audio)
+ {
+ omx_err = m_omx_clock.EnablePort(m_omx_clock.GetInputPort(), true);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::StateExecute - Error enable port %d on component %s omx_err(0x%08x)",
+ m_omx_clock.GetInputPort(), m_omx_clock.GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ if(m_has_video)
+ {
+ omx_err = m_omx_clock.EnablePort(m_omx_clock.GetInputPort() + 1, true);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::StateExecute - Error enable port %d on component %s omx_err(0x%08x)",
+ m_omx_clock.GetInputPort(), m_omx_clock.GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
+ clock.nStartTime = ToOMXTime(0LL);
+ clock.nOffset = ToOMXTime(0LL);
+ clock.nWaitMask = 0;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::OMXStateExecute error setting OMX_IndexConfigTimeClockState\n");
+ }
+ */
+
+ //OMXStart(lock);
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+void OMXClock::OMXStateIdle(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return;
+
+ if(lock)
+ Lock();
+
+ if(m_omx_clock.GetState() == OMX_StateExecuting)
+ m_omx_clock.SetStateForComponent(OMX_StatePause);
+
+ if(m_omx_clock.GetState() != OMX_StateIdle)
+ m_omx_clock.SetStateForComponent(OMX_StateIdle);
+
+ if(lock)
+ UnLock();
+}
+
+COMXCoreComponent *OMXClock::GetOMXClock()
+{
+ return &m_omx_clock;
+}
+
+void OMXClock::OMXSaveState(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_INIT_STRUCTURE(m_clock_state);
+
+ omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeClockState, &m_clock_state);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "OMXClock::SaveState error geting OMX_IndexConfigTimeClockState\n");
+
+ if(lock)
+ UnLock();
+}
+
+void OMXClock::OMXRestoreState(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &m_clock_state);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "OMXClock::RestoreState error setting OMX_IndexConfigTimeClockState\n");
+
+ if(lock)
+ UnLock();
+}
+
+bool OMXClock::OMXStop(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXStop\n");
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateStopped;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::Stop error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+bool OMXClock::OMXStart(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXStart\n");
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateRunning;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::Start error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+void OMXClock::VideoStart(bool video_start)
+{
+ Lock();
+ m_video_start = video_start;
+ UnLock();
+};
+
+void OMXClock::AudioStart(bool audio_start)
+{
+ Lock();
+ m_audio_start = audio_start;
+ UnLock();
+};
+
+bool OMXClock::OMXReset(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXReset 0x%08x\n", m_omx_clock.GetState());
+
+ m_audio_buffer = false;
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!OMXSetReferenceClock(false))
+ {
+ UnLock();
+ return false;
+ }
+
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
+ //clock.nOffset = ToOMXTime(-1000LL * 200);
+
+ OMXSetClockPorts(&clock);
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::OMXReset error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+double OMXClock::OMXWallTime(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return 0;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ double pts = 0;
+
+ OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
+ OMX_INIT_STRUCTURE(timeStamp);
+ timeStamp.nPortIndex = m_omx_clock.GetInputPort();
+
+ omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentWallTime, &timeStamp);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::WallTime error getting OMX_IndexConfigTimeCurrentWallTime\n");
+ if(lock)
+ UnLock();
+ return 0;
+ }
+
+ pts = FromOMXTime(timeStamp.nTimestamp);
+
+ if(lock)
+ UnLock();
+
+ return pts;
+}
+
+double OMXClock::OMXMediaTime(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return 0;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ double pts = 0;
+
+ OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
+ OMX_INIT_STRUCTURE(timeStamp);
+ timeStamp.nPortIndex = m_omx_clock.GetInputPort();
+
+ omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime\n");
+ if(lock)
+ UnLock();
+ return 0;
+ }
+
+ pts = FromOMXTime(timeStamp.nTimestamp);
+ if(lock)
+ UnLock();
+
+ return pts;
+}
+
+bool OMXClock::OMXPause(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(m_pause)
+ return true;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_SCALETYPE scaleType;
+ OMX_INIT_STRUCTURE(scaleType);
+
+ scaleType.xScale = 0; // pause
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::Pause error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXPause\n");
+
+ m_pause = true;
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+bool OMXClock::OMXResume(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(!m_pause)
+ return true;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_SCALETYPE scaleType;
+ OMX_INIT_STRUCTURE(scaleType);
+
+ scaleType.xScale = (1<<16); // normal speed
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::Resume error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ m_pause = false;
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXResume\n");
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+bool OMXClock::OMXUpdateClock(double pts, bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_TIMESTAMPTYPE ts;
+ OMX_INIT_STRUCTURE(ts);
+
+ ts.nPortIndex = OMX_ALL;
+ ts.nTimestamp = ToOMXTime((uint64_t)pts);
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXUpdateClock %f", pts / DVD_TIME_BASE);
+
+ if(m_has_audio)
+ {
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeCurrentAudioReference, &ts);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "OMXClock::OMXUpdateClock error setting OMX_IndexConfigTimeCurrentAudioReference\n");
+ }
+ else
+ {
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeCurrentVideoReference, &ts);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "OMXClock::OMXUpdateClock error setting OMX_IndexConfigTimeCurrentVideoReference\n");
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+bool OMXClock::OMXWaitStart(double pts, bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
+ OMXSetClockPorts(&clock);
+ clock.nStartTime = ToOMXTime((uint64_t)pts);
+ //clock.nOffset = ToOMXTime(-1000LL * 200);
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::OMXWaitStart error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+void OMXClock::OMXHandleBackward(bool lock /* = true */)
+{
+ /*
+ if(m_omx_clock.GetComponent() == NULL)
+ return;
+
+ if(lock)
+ Lock();
+
+ if(m_omx_speed < 0)
+ {
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
+ OMX_INIT_STRUCTURE(clock);
+
+ clock.eState = OMX_TIME_ClockStateRunning;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::OMXHandleBackward error setting OMX_IndexConfigTimeClockState\n");
+ }
+ }
+
+ if(lock)
+ UnLock();
+ */
+}
+
+bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(m_pause)
+ return true;
+
+ if(lock)
+ Lock();
+
+ m_omx_speed = speed;
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXSetSpeed fake %d\n\n", m_omx_speed / DVD_PLAYSPEED_NORMAL);
+
+ // only adjust speed when not audio buffering
+ if(!m_audio_buffer)
+ {
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_SCALETYPE scaleType;
+ OMX_INIT_STRUCTURE(scaleType);
+
+ scaleType.xScale = ((m_omx_speed / DVD_PLAYSPEED_NORMAL) << 16);
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXSetSpeed real %d", m_omx_speed / DVD_PLAYSPEED_NORMAL);
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::OMXSetSpeed error setting OMX_IndexConfigTimeClockState\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+void OMXClock::AddTimespecs(struct timespec &time, long millisecs)
+{
+ time.tv_sec += millisecs / 1000;
+ time.tv_nsec += (millisecs % 1000) * 1000000;
+ if (time.tv_nsec > 1000000000)
+ {
+ time.tv_sec += 1;
+ time.tv_nsec -= 1000000000;
+ }
+}
+
+bool OMXClock::HDMIClockSync(bool lock /* = true */)
+{
+ if(m_omx_clock.GetComponent() == NULL)
+ return false;
+
+ if(lock)
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
+ OMX_INIT_STRUCTURE(latencyTarget);
+
+ latencyTarget.nPortIndex = OMX_ALL;
+ latencyTarget.bEnabled = OMX_TRUE;
+ latencyTarget.nFilter = 10;
+ latencyTarget.nTarget = 0;
+ latencyTarget.nShift = 3;
+ latencyTarget.nSpeedFactor = -200;
+ latencyTarget.nInterFactor = 100;
+ latencyTarget.nAdjCap = 100;
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigLatencyTarget, &latencyTarget);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "OMXClock::Speed error setting OMX_IndexConfigLatencyTarget\n");
+ if(lock)
+ UnLock();
+ return false;
+ }
+
+ if(lock)
+ UnLock();
+
+ return true;
+}
+
+int64_t OMXClock::CurrentHostCounter(void)
+{
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return( ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec );
+}
+
+int64_t OMXClock::CurrentHostFrequency(void)
+{
+ return( (int64_t)1000000000L );
+}
+
+void OMXClock::AddTimeSpecNano(struct timespec &time, uint64_t nanoseconds)
+{
+ time.tv_sec += nanoseconds / 1000000000;
+ time.tv_nsec += (nanoseconds % 1000000000);
+ if (time.tv_nsec > 1000000000)
+ {
+ time.tv_sec += 1;
+ time.tv_nsec -= 1000000000;
+ }
+}
+
+int OMXClock::GetRefreshRate(double* interval)
+{
+ if(!interval)
+ return false;
+
+ *interval = m_fps;
+ return true;
+}
+
+void OMXClock::OMXAudioBufferStart()
+{
+ Lock();
+
+ m_audio_buffer = true;
+
+ if(m_omx_clock.GetComponent() == NULL)
+ {
+ UnLock();
+ return;
+ }
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_TIME_CONFIG_SCALETYPE scaleType;
+ OMX_INIT_STRUCTURE(scaleType);
+
+ scaleType.xScale = 0;
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXAudioBufferStart");
+
+ omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType);
+ if(omx_err != OMX_ErrorNone)
+ CLog::Log(LOGERROR, "OMXClock::OMXAudioBufferStart error setting OMX_IndexConfigTimeClockState\n");
+
+ UnLock();
+}
+
+void OMXClock::OMXAudioBufferStop()
+{
+ Lock();
+
+ CLog::Log(LOGDEBUG, "OMXClock::OMXAudioBufferStop");
+
+ m_audio_buffer = false;
+
+ OMXSetSpeed(m_omx_speed, false);
+
+ UnLock();
+}
+
+double OMXClock::NormalizeFrameduration(double frameduration)
+{
+ //if the duration is within 20 microseconds of a common duration, use that
+ const double durations[] = {DVD_TIME_BASE * 1.001 / 24.0, DVD_TIME_BASE / 24.0, DVD_TIME_BASE / 25.0,
+ DVD_TIME_BASE * 1.001 / 30.0, DVD_TIME_BASE / 30.0, DVD_TIME_BASE / 50.0,
+ DVD_TIME_BASE * 1.001 / 60.0, DVD_TIME_BASE / 60.0};
+
+ double lowestdiff = DVD_TIME_BASE;
+ int selected = -1;
+ for (size_t i = 0; i < sizeof(durations) / sizeof(durations[0]); i++)
+ {
+ double diff = fabs(frameduration - durations[i]);
+ if (diff < DVD_MSEC_TO_TIME(0.02) && diff < lowestdiff)
+ {
+ selected = i;
+ lowestdiff = diff;
+ }
+ }
+
+ if (selected != -1)
+ return durations[selected];
+ else
+ return frameduration;
+}
View
154 xbmc/linux/OMXClock.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2005-2008 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, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#ifndef _AVCLOCK_H_
+#define _AVCLOCK_H_
+
+#include "OMXCore.h"
+#include "DVDClock.h"
+#include "linux/XTimeUtils.h"
+
+#ifdef OMX_SKIP64BIT
+static inline OMX_TICKS ToOMXTime(int64_t pts)
+{
+ OMX_TICKS ticks;
+ ticks.nLowPart = pts;
+ ticks.nHighPart = pts >> 32;
+ return ticks;
+}
+static inline uint64_t FromOMXTime(OMX_TICKS ticks)
+{
+ uint64_t pts = ticks.nLowPart | ((uint64_t)ticks.nHighPart << 32);
+ return pts;
+}
+#else
+#define FromOMXTime(x) (x)
+#define ToOMXTime(x) (x)
+#endif
+
+enum {
+ AV_SYNC_AUDIO_MASTER,
+ AV_SYNC_VIDEO_MASTER,
+ AV_SYNC_EXTERNAL_MASTER,
+};
+
+class OMXClock
+{
+protected:
+ bool m_pause;
+ bool m_has_video;
+ bool m_has_audio;
+ int m_play_speed;
+ pthread_mutex_t m_lock;
+ double SystemToAbsolute(int64_t system);
+ double SystemToPlaying(int64_t system);
+ int64_t m_systemUsed;
+ int64_t m_startClock;
+ int64_t m_pauseClock;
+ double m_iDisc;
+ bool m_bReset;
+ static int64_t m_systemFrequency;
+ static int64_t m_systemOffset;
+ int64_t m_ClockOffset;
+ double m_maxspeedadjust;
+ bool m_speedadjust;
+ static bool m_ismasterclock;
+ double m_fps;
+ int m_omx_speed;
+ bool m_video_start;
+ bool m_audio_start;
+ bool m_audio_buffer;
+ CDVDClock m_clock;
+ OMX_TIME_CONFIG_CLOCKSTATETYPE m_clock_state;
+private:
+ COMXCoreComponent m_omx_clock;
+public:
+ OMXClock();
+ ~OMXClock();
+ void Lock();
+ void UnLock();
+ double GetAbsoluteClock(bool interpolated = true);
+ double GetFrequency() { return (double)m_systemFrequency ; }
+ double WaitAbsoluteClock(double target);
+ double GetClock(bool interpolated = true);
+ double GetClock(double& absolute, bool interpolated = true);
+ void CheckSystemClock();
+ void SetSpeed(int iSpeed);
+ void SetMasterClock(bool ismasterclock) { m_ismasterclock = ismasterclock; }
+ bool IsMasterClock() { return m_ismasterclock; }
+ void Discontinuity(double currentPts = 0LL);
+
+ void Reset() { m_bReset = true; }
+ void Pause();
+ void Resume();
+
+ int UpdateFramerate(double fps, double* interval = NULL);
+ bool SetMaxSpeedAdjust(double speed);
+
+ void OMXSetClockPorts(OMX_TIME_CONFIG_CLOCKSTATETYPE *clock);
+ bool OMXSetReferenceClock(bool lock = true);
+ bool OMXInitialize(bool has_video, bool has_audio);
+ void OMXDeinitialize();
+ bool OMXIsPaused() { return m_pause; };
+ void OMXSaveState(bool lock = true);
+ void OMXRestoreState(bool lock = true);
+ bool OMXStop(bool lock = true);
+ bool OMXStart(bool lock = true);
+ bool OMXReset(bool lock = true);
+ double OMXWallTime(bool lock = true);
+ double OMXMediaTime(bool lock = true);
+ bool OMXPause(bool lock = true);
+ bool OMXResume(bool lock = true);
+ bool OMXUpdateClock(double pts, bool lock = true);
+ bool OMXWaitStart(double pts, bool lock = true);
+ void OMXHandleBackward(bool lock = true);
+ bool OMXSetSpeed(int speed, bool lock = true);
+ int OMXPlaySpeed() { return m_omx_speed; };
+ int OMXGetPlaySpeed() { return m_omx_speed; };
+ COMXCoreComponent *GetOMXClock();
+ bool OMXStatePause(bool lock = true);
+ bool OMXStateExecute(bool lock = true);
+ void OMXStateIdle(bool lock = true);
+ static void AddTimespecs(struct timespec &time, long millisecs);
+ bool HDMIClockSync(bool lock = true);
+ static int64_t CurrentHostCounter(void);
+ static int64_t CurrentHostFrequency(void);
+ bool HasVideo() { return m_has_video; };
+ bool HasAudio() { return m_has_audio; };
+ void HasVideo(bool has_video) { m_has_video = has_video; };
+ void HasAudio(bool has_audio) { m_has_audio = has_audio; };
+ bool VideoStart() { return m_video_start; };
+ bool AudioStart() { return m_audio_start; };
+ void VideoStart(bool video_start);
+ void AudioStart(bool audio_start);
+ static void AddTimeSpecNano(struct timespec &time, uint64_t nanoseconds);
+
+ void OMXAudioBufferStart();
+ void OMXAudioBufferStop();
+ bool OMXAudioBuffer() { return m_audio_buffer; };
+
+ int GetRefreshRate(double* interval = NULL);
+ void SetRefreshRate(double fps) { m_fps = fps; };
+
+ static double NormalizeFrameduration(double frameduration);
+};
+
+#endif
View
1,722 xbmc/linux/OMXCore.cpp
@@ -0,0 +1,1722 @@
+/*
+ * Copyright (C) 2010 Team XBMCn
+ * 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, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#if (defined HAVE_CONFIG_H) && (!defined WIN32)
+ #include "config.h"
+#elif defined(_WIN32)
+#include "system.h"
+#endif
+
+#include <math.h>
+#include <sys/time.h>
+
+//#include "linux/XTimeUtils.h"
+
+#if defined(HAVE_OMXLIB)
+#include "OMXCore.h"
+#include "utils/log.h"
+
+#include "OMXClock.h"
+
+#ifdef _LINUX
+#include "XMemUtils.h"
+#endif
+
+//#define OMX_USEBUFFER
+
+//#define OMX_DEBUG_EVENTS
+//#define OMX_DEBUG_EVENTHANDLER
+
+////////////////////////////////////////////////////////////////////////////////////////////
+#define CLASSNAME "COMXCoreComponent"
+////////////////////////////////////////////////////////////////////////////////////////////
+
+static void add_timespecs(struct timespec &time, long millisecs)
+{
+ time.tv_sec += millisecs / 1000;
+ time.tv_nsec += (millisecs % 1000) * 1000000;
+ if (time.tv_nsec > 1000000000)
+ {
+ time.tv_sec += 1;
+ time.tv_nsec -= 1000000000;
+ }
+}
+
+
+COMXCoreTunel::COMXCoreTunel()
+{
+ m_src_component = NULL;
+ m_dst_component = NULL;
+ m_src_port = 0;
+ m_dst_port = 0;
+ m_portSettingsChanged = false;
+ m_DllOMX = new DllOMX();
+ m_DllOMXOpen = m_DllOMX->Load();
+
+ pthread_mutex_init(&m_lock, NULL);
+}
+
+COMXCoreTunel::~COMXCoreTunel()
+{
+ Deestablish();
+ if(m_DllOMXOpen)
+ m_DllOMX->Unload();
+ delete m_DllOMX;
+
+ pthread_mutex_destroy(&m_lock);
+}
+
+void COMXCoreTunel::Lock()
+{
+ pthread_mutex_lock(&m_lock);
+}
+
+void COMXCoreTunel::UnLock()
+{
+ pthread_mutex_unlock(&m_lock);
+}
+
+void COMXCoreTunel::Initialize(COMXCoreComponent *src_component, unsigned int src_port, COMXCoreComponent *dst_component, unsigned int dst_port)
+{
+ if(!m_DllOMXOpen)
+ return;
+ m_src_component = src_component;
+ m_src_port = src_port;
+ m_dst_component = dst_component;
+ m_dst_port = dst_port;
+}
+
+OMX_ERRORTYPE COMXCoreTunel::Flush()
+{
+ if(!m_DllOMXOpen)
+ return OMX_ErrorUndefined;
+
+ if(!m_src_component || !m_dst_component)
+ return OMX_ErrorUndefined;
+
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ if(m_src_component->GetComponent())
+ {
+ omx_err = OMX_SendCommand(m_src_component->GetComponent(), OMX_CommandFlush, m_src_port, NULL);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Flush - Error flush port %d on component %s omx_err(0x%08x)",
+ m_src_port, m_src_component->GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ if(m_dst_component->GetComponent())
+ {
+ omx_err = OMX_SendCommand(m_dst_component->GetComponent(), OMX_CommandFlush, m_dst_port, NULL);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Flush - Error flush port %d on component %s omx_err(0x%08x)",
+ m_dst_port, m_dst_component->GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ if(m_src_component->GetComponent())
+ omx_err = m_src_component->WaitForCommand(OMX_CommandFlush, m_src_port);
+
+ if(m_dst_component->GetComponent())
+ omx_err = m_dst_component->WaitForCommand(OMX_CommandFlush, m_dst_port);
+
+ UnLock();
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE COMXCoreTunel::Deestablish(bool noWait)
+{
+ if(!m_DllOMXOpen)
+ return OMX_ErrorUndefined;
+
+ if(!m_src_component || !m_dst_component)
+ return OMX_ErrorUndefined;
+
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(m_src_component->GetComponent() && m_portSettingsChanged && !noWait)
+ omx_err = m_src_component->WaitForEvent(OMX_EventPortSettingsChanged);
+
+ if(m_src_component->GetComponent())
+ {
+ omx_err = m_src_component->DisablePort(m_src_port, false);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Deestablish - Error disable port %d on component %s omx_err(0x%08x)",
+ m_src_port, m_src_component->GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ if(m_dst_component->GetComponent())
+ {
+ omx_err = m_dst_component->DisablePort(m_dst_port, false);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Deestablish - Error disable port %d on component %s omx_err(0x%08x)",
+ m_dst_port, m_dst_component->GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ if(m_src_component->GetComponent())
+ {
+ omx_err = m_DllOMX->OMX_SetupTunnel(m_src_component->GetComponent(), m_src_port, NULL, 0);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorIncorrectStateOperation)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Deestablish - could not unset tunnel on comp src %s port %d omx_err(0x%08x)\n",
+ m_src_component->GetName().c_str(), m_src_port, (int)omx_err);
+ }
+ }
+
+ if(m_dst_component->GetComponent())
+ {
+ omx_err = m_DllOMX->OMX_SetupTunnel(m_dst_component->GetComponent(), m_dst_port, NULL, 0);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorIncorrectStateOperation)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Deestablish - could not unset tunnel on comp dst %s port %d omx_err(0x%08x)\n",
+ m_dst_component->GetName().c_str(), m_dst_port, (int)omx_err);
+ }
+ }
+
+ UnLock();
+
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE COMXCoreTunel::Establish(bool portSettingsChanged)
+{
+ if(!m_DllOMXOpen)
+ return OMX_ErrorUndefined;
+
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_PARAM_U32TYPE param;
+ OMX_INIT_STRUCTURE(param);
+
+ if(!m_src_component || !m_dst_component)
+ {
+ UnLock();
+ return OMX_ErrorUndefined;
+ }
+
+ if(m_src_component->GetState() == OMX_StateLoaded)
+ {
+ omx_err = m_src_component->SetStateForComponent(OMX_StateIdle);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - Error setting state to idle %s omx_err(0x%08x)",
+ m_src_component->GetName().c_str(), (int)omx_err);
+ UnLock();
+ return omx_err;
+ }
+ }
+
+ if(portSettingsChanged)
+ {
+ omx_err = m_src_component->WaitForEvent(OMX_EventPortSettingsChanged);
+ if(omx_err != OMX_ErrorNone)
+ {
+ UnLock();
+ return omx_err;
+ }
+ }
+
+ if(m_src_component->GetComponent())
+ {
+ omx_err = m_src_component->DisablePort(m_src_port, false);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - Error disable port %d on component %s omx_err(0x%08x)",
+ m_src_port, m_src_component->GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ if(m_dst_component->GetComponent())
+ {
+ omx_err = m_dst_component->DisablePort(m_dst_port, false);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState) {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - Error disable port %d on component %s omx_err(0x%08x)",
+ m_dst_port, m_dst_component->GetName().c_str(), (int)omx_err);
+ }
+ }
+
+ /*
+ OMX_INIT_STRUCTURE(param);
+ param.nPortIndex = m_src_port;
+ omx_err = m_src_component->GetParameter(OMX_IndexParamNumAvailableStreams, &param);
+ if(omx_err == OMX_ErrorNone)
+ {
+ param.nU32 = 0;
+ m_src_component->SetParameter(OMX_IndexParamActiveStream, &param);
+ }
+ */
+
+ if(m_src_component->GetComponent() && m_dst_component->GetComponent())
+ {
+ omx_err = m_DllOMX->OMX_SetupTunnel(m_src_component->GetComponent(), m_src_port, m_dst_component->GetComponent(), m_dst_port);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - could not setup tunnel src %s port %d dst %s port %d omx_err(0x%08x)\n",
+ m_src_component->GetName().c_str(), m_src_port, m_dst_component->GetName().c_str(), m_dst_port, (int)omx_err);
+ UnLock();
+ return omx_err;
+ }
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - could not setup tunnel\n");
+ UnLock();
+ return OMX_ErrorUndefined;
+ }
+
+ if(m_src_component->GetComponent())
+ {
+ omx_err = m_src_component->EnablePort(m_src_port, false);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - Error enable port %d on component %s omx_err(0x%08x)",
+ m_src_port, m_src_component->GetName().c_str(), (int)omx_err);
+ UnLock();
+ return omx_err;
+ }
+ }
+
+ if(m_dst_component->GetComponent())
+ {
+ omx_err = m_dst_component->EnablePort(m_dst_port, false);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - Error enable port %d on component %s omx_err(0x%08x)",
+ m_dst_port, m_dst_component->GetName().c_str(), (int)omx_err);
+ UnLock();
+ return omx_err;
+ }
+ }
+
+ if(m_dst_component->GetComponent())
+ {
+ if(m_dst_component->GetState() == OMX_StateLoaded)
+ {
+ omx_err = m_dst_component->WaitForCommand(OMX_CommandPortEnable, m_dst_port);
+ if(omx_err != OMX_ErrorNone)
+ {
+ UnLock();
+ return omx_err;
+ }
+
+ omx_err = m_dst_component->SetStateForComponent(OMX_StateIdle);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::Establish - Error setting state to idle %s omx_err(0x%08x)",
+ m_src_component->GetName().c_str(), (int)omx_err);
+ UnLock();
+ return omx_err;
+ }
+ }
+ else
+ {
+ omx_err = m_dst_component->WaitForCommand(OMX_CommandPortEnable, m_dst_port);
+ if(omx_err != OMX_ErrorNone)
+ {
+ UnLock();
+ return omx_err;
+ }
+ }
+ }
+
+ if(m_src_component->GetComponent())
+ {
+ omx_err = m_src_component->WaitForCommand(OMX_CommandPortEnable, m_src_port);
+ if(omx_err != OMX_ErrorNone)
+ {
+ UnLock();
+ return omx_err;
+ }
+ }
+
+ m_portSettingsChanged = portSettingsChanged;
+
+ UnLock();
+
+ return OMX_ErrorNone;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+
+COMXCoreComponent::COMXCoreComponent()
+{
+ m_input_port = 0;
+ m_output_port = 0;
+ m_handle = NULL;
+
+ m_input_alignment = 0;
+ m_input_buffer_size = 0;
+ m_input_buffer_count = 0;
+
+ m_output_alignment = 0;
+ m_output_buffer_size = 0;
+ m_output_buffer_count = 0;
+ m_flush_input = false;
+ m_flush_output = false;
+
+ m_eos = false;
+
+ m_exit = false;
+ m_DllOMXOpen = false;
+
+ pthread_mutex_init(&m_omx_input_mutex, NULL);
+ pthread_mutex_init(&m_omx_output_mutex, NULL);
+ pthread_mutex_init(&m_omx_event_mutex, NULL);
+ pthread_cond_init(&m_input_buffer_cond, NULL);
+ pthread_cond_init(&m_output_buffer_cond, NULL);
+ pthread_cond_init(&m_omx_event_cond, NULL);
+
+ for(int i = 0; i < OMX_MAX_PORTS; i++)
+ m_ports_enabled[i] = -1;
+
+ m_DllOMX = new DllOMX();
+
+ pthread_mutex_init(&m_lock, NULL);
+}
+
+COMXCoreComponent::~COMXCoreComponent()
+{
+ Deinitialize();
+
+ pthread_mutex_destroy(&m_omx_input_mutex);
+ pthread_mutex_destroy(&m_omx_output_mutex);
+ pthread_mutex_destroy(&m_omx_event_mutex);
+ pthread_cond_destroy(&m_input_buffer_cond);
+ pthread_cond_destroy(&m_output_buffer_cond);
+ pthread_cond_destroy(&m_omx_event_cond);
+
+ pthread_mutex_destroy(&m_lock);
+
+ delete m_DllOMX;
+}
+
+void COMXCoreComponent::Lock()
+{
+ pthread_mutex_lock(&m_lock);
+}
+
+void COMXCoreComponent::UnLock()
+{
+ pthread_mutex_unlock(&m_lock);
+}
+
+OMX_ERRORTYPE COMXCoreComponent::EmptyThisBuffer(OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle || !omx_buffer)
+ return OMX_ErrorUndefined;
+
+ omx_err = OMX_EmptyThisBuffer(m_handle, omx_buffer);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::EmptyThisBuffer component(%s) - failed with result(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::FillThisBuffer(OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle || !omx_buffer)
+ return OMX_ErrorUndefined;
+
+ omx_err = OMX_FillThisBuffer(m_handle, omx_buffer);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::FillThisBuffer component(%s) - failed with result(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::FreeOutputBuffer(OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle || !omx_buffer)
+ return OMX_ErrorUndefined;
+
+ omx_err = OMX_FreeBuffer(m_handle, m_output_port, omx_buffer);
+ if (omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::FreeOutputBuffer component(%s) - failed with result(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ return omx_err;
+}
+
+unsigned int COMXCoreComponent::GetInputBufferSize()
+{
+ int free = m_input_buffer_count * m_input_buffer_size;
+ return free;
+}
+
+unsigned int COMXCoreComponent::GetOutputBufferSize()
+{
+ int free = m_output_buffer_count * m_output_buffer_size;
+ return free;
+}
+
+unsigned int COMXCoreComponent::GetInputBufferSpace()
+{
+ int free = m_omx_input_avaliable.size() * m_input_buffer_size;
+ return free;
+}
+
+unsigned int COMXCoreComponent::GetOutputBufferSpace()
+{
+ int free = m_omx_output_available.size() * m_output_buffer_size;
+ return free;
+}
+
+void COMXCoreComponent::FlushAll()
+{
+ FlushInput();
+ FlushOutput();
+}
+
+void COMXCoreComponent::FlushInput()
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ omx_err = OMX_SendCommand(m_handle, OMX_CommandFlush, m_input_port, NULL);
+
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - Error on component %s omx_err(0x%08x)",
+ m_componentName.c_str(), (int)omx_err);
+ }
+ WaitForCommand(OMX_CommandFlush, m_input_port);
+
+ UnLock();
+}
+
+void COMXCoreComponent::FlushOutput()
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ omx_err = OMX_SendCommand(m_handle, OMX_CommandFlush, m_output_port, NULL);
+
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - Error on component %s omx_err(0x%08x)",
+ m_componentName.c_str(), (int)omx_err);
+ }
+ WaitForCommand(OMX_CommandFlush, m_output_port);
+
+ UnLock();
+}
+
+// timeout in milliseconds
+OMX_BUFFERHEADERTYPE *COMXCoreComponent::GetInputBuffer(long timeout)
+{
+ OMX_BUFFERHEADERTYPE *omx_input_buffer = NULL;
+
+ if(!m_handle)
+ return NULL;
+
+ pthread_mutex_lock(&m_omx_input_mutex);
+ struct timespec endtime;
+ clock_gettime(CLOCK_REALTIME, &endtime);
+ add_timespecs(endtime, timeout);
+ while (1 && !m_flush_input)
+ {
+ if(!m_omx_input_avaliable.empty())
+ {
+ omx_input_buffer = m_omx_input_avaliable.front();
+ m_omx_input_avaliable.pop();
+ break;
+ }
+
+ int retcode = pthread_cond_timedwait(&m_input_buffer_cond, &m_omx_input_mutex, &endtime);
+ if (retcode != 0) {
+ CLog::Log(LOGERROR, "COMXCoreComponent::GetInputBuffer %s wait event timeout\n", m_componentName.c_str());
+ break;
+ }
+ }
+ pthread_mutex_unlock(&m_omx_input_mutex);
+ return omx_input_buffer;
+}
+
+// timeout in milliseconds
+OMX_BUFFERHEADERTYPE *COMXCoreComponent::GetOutputBuffer(long timeout)
+{
+ OMX_BUFFERHEADERTYPE *omx_output_buffer = NULL;
+
+ if(!m_handle)
+ return NULL;
+
+ pthread_mutex_lock(&m_omx_output_mutex);
+ struct timespec endtime;
+ clock_gettime(CLOCK_REALTIME, &endtime);
+ add_timespecs(endtime, timeout);
+ //while (1 && !m_flush_output)
+ //{
+ if(!m_omx_output_available.empty())
+ {
+ omx_output_buffer = m_omx_output_available.front();
+ m_omx_output_available.pop();
+ //break;
+ }
+
+ // int retcode = pthread_cond_timedwait(&m_output_buffer_cond, &m_omx_output_mutex, &endtime);
+ // if (retcode != 0) {
+ // CLog::Log(LOGERROR, "COMXCoreComponent::GetOutputBuffer %s wait event timeout\n", m_componentName.c_str());
+ // break;
+ // }
+ //}
+ pthread_mutex_unlock(&m_omx_output_mutex);
+ return omx_output_buffer;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::AllocInputBuffers(void)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle)
+ return OMX_ErrorUndefined;
+
+ OMX_PARAM_PORTDEFINITIONTYPE portFormat;
+ OMX_INIT_STRUCTURE(portFormat);
+ portFormat.nPortIndex = m_input_port;
+
+ omx_err = OMX_GetParameter(m_handle, OMX_IndexParamPortDefinition, &portFormat);
+ if(omx_err != OMX_ErrorNone)
+ return omx_err;
+
+ if(GetState() != OMX_StateIdle)
+ {
+ if(GetState() != OMX_StateLoaded)
+ SetStateForComponent(OMX_StateLoaded);
+
+ SetStateForComponent(OMX_StateIdle);
+ }
+
+ omx_err = EnablePort(m_input_port, false);
+ if(omx_err != OMX_ErrorNone)
+ return omx_err;
+
+ if(GetState() == OMX_StateLoaded)
+ SetStateForComponent(OMX_StateIdle);
+
+ m_input_alignment = portFormat.nBufferAlignment;
+ m_input_buffer_count = portFormat.nBufferCountActual;
+ m_input_buffer_size = portFormat.nBufferSize;
+
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::AllocInputBuffers component(%s) - port(%d), nBufferCountMin(%lu), nBufferCountActual(%lu), nBufferSize(%lu), nBufferAlignmen(%lu)\n",
+ m_componentName.c_str(), GetInputPort(), portFormat.nBufferCountMin,
+ portFormat.nBufferCountActual, portFormat.nBufferSize, portFormat.nBufferAlignment);
+
+ for (size_t i = 0; i < portFormat.nBufferCountActual; i++)
+ {
+ OMX_BUFFERHEADERTYPE *buffer = NULL;
+#ifdef OMX_USEBUFFER
+ OMX_U8* data = (OMX_U8*)_aligned_malloc(portFormat.nBufferSize, m_input_alignment);
+ omx_err = OMX_UseBuffer(m_handle, &buffer, m_input_port, NULL, portFormat.nBufferSize, data);
+#else
+ omx_err = OMX_AllocateBuffer(m_handle, &buffer, m_input_port, NULL, portFormat.nBufferSize);
+#endif
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::AllocInputBuffers component(%s) - OMX_UseBuffer failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+#ifdef OMX_USEBUFFER
+ _aligned_free(data);
+#endif
+ return omx_err;
+ }
+ buffer->nInputPortIndex = m_input_port;
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->pAppPrivate = (void*)i;
+ m_omx_input_buffers.push_back(buffer);
+ m_omx_input_avaliable.push(buffer);
+ }
+
+ omx_err = WaitForCommand(OMX_CommandPortEnable, m_input_port);
+
+ m_flush_input = false;
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::AllocOutputBuffers(void)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle)
+ return OMX_ErrorUndefined;
+
+ OMX_PARAM_PORTDEFINITIONTYPE portFormat;
+ OMX_INIT_STRUCTURE(portFormat);
+ portFormat.nPortIndex = m_output_port;
+
+ omx_err = OMX_GetParameter(m_handle, OMX_IndexParamPortDefinition, &portFormat);
+ if(omx_err != OMX_ErrorNone)
+ return omx_err;
+
+ if(GetState() != OMX_StateIdle)
+ {
+ if(GetState() != OMX_StateLoaded)
+ SetStateForComponent(OMX_StateLoaded);
+
+ SetStateForComponent(OMX_StateIdle);
+ }
+
+ omx_err = EnablePort(m_output_port, false);
+ if(omx_err != OMX_ErrorNone)
+ return omx_err;
+
+ if(GetState() == OMX_StateLoaded)
+ SetStateForComponent(OMX_StateIdle);
+
+ m_output_alignment = portFormat.nBufferAlignment;
+ m_output_buffer_count = portFormat.nBufferCountActual;
+ m_output_buffer_size = portFormat.nBufferSize;
+
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::AllocOutputBuffers component(%s) - port(%d), nBufferCountMin(%lu), nBufferCountActual(%lu), nBufferSize(%lu) nBufferAlignmen(%lu)\n",
+ m_componentName.c_str(), m_output_port, portFormat.nBufferCountMin,
+ portFormat.nBufferCountActual, portFormat.nBufferSize, portFormat.nBufferAlignment);
+
+ for (size_t i = 0; i < portFormat.nBufferCountActual; i++)
+ {
+ OMX_BUFFERHEADERTYPE *buffer = NULL;
+#ifdef OMX_USEBUFFER
+ OMX_U8* data = (OMX_U8*)_aligned_malloc(portFormat.nBufferSize, m_output_alignment);
+ omx_err = OMX_UseBuffer(m_handle, &buffer, m_output_port, NULL, portFormat.nBufferSize, data);
+#else
+ omx_err = OMX_AllocateBuffer(m_handle, &buffer, m_output_port, NULL, portFormat.nBufferSize);
+#endif
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::AllocOutputBuffers component(%s) - OMX_UseBuffer failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+#ifdef OMX_USEBUFFER
+ _aligned_free(data);
+#endif
+ return omx_err;
+ }
+ buffer->nOutputPortIndex = m_output_port;
+ buffer->nFilledLen = 0;
+ buffer->nOffset = 0;
+ buffer->pAppPrivate = (void*)i;
+ m_omx_output_buffers.push_back(buffer);
+ m_omx_output_available.push(buffer);
+ }
+
+ omx_err = WaitForCommand(OMX_CommandPortEnable, m_output_port);
+
+ m_flush_output = false;
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::FreeInputBuffers(bool wait)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle)
+ return OMX_ErrorUndefined;
+
+ if(m_omx_input_buffers.empty())
+ return OMX_ErrorNone;
+
+ m_flush_input = true;
+
+ pthread_mutex_lock(&m_omx_input_mutex);
+ pthread_cond_broadcast(&m_input_buffer_cond);
+
+ omx_err = DisablePort(m_input_port, wait);
+
+ assert(m_omx_input_buffers.size() == m_omx_input_avaliable.size());
+
+ for (size_t i = 0; i < m_omx_input_buffers.size(); i++)
+ {
+#ifdef OMX_USEBUFFER
+ uint8_t *buf = m_omx_input_buffers[i]->pBuffer;
+#endif
+ omx_err = OMX_FreeBuffer(m_handle, m_input_port, m_omx_input_buffers[i]);
+#ifdef OMX_USEBUFFER
+ if(buf)
+ _aligned_free(buf);
+#endif
+ //m_omx_input_buffers[i]->pBuffer = NULL;
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::FreeInputBuffers error deallocate omx input buffer on component %s omx_err(0x%08x)\n", m_componentName.c_str(), omx_err);
+ }
+ }
+
+ m_omx_input_buffers.clear();
+
+ while (!m_omx_input_avaliable.empty())
+ m_omx_input_avaliable.pop();
+
+ m_input_alignment = 0;
+ m_input_buffer_size = 0;
+ m_input_buffer_count = 0;
+
+ pthread_mutex_unlock(&m_omx_input_mutex);
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::FreeOutputBuffers(bool wait)
+{
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle)
+ return OMX_ErrorUndefined;
+
+ if(m_omx_output_buffers.empty())
+ return OMX_ErrorNone;
+
+ m_flush_output = true;
+
+ pthread_mutex_lock(&m_omx_output_mutex);
+ pthread_cond_broadcast(&m_output_buffer_cond);
+
+ omx_err = DisablePort(m_output_port, false);
+
+ assert(m_omx_output_buffers.size() == m_omx_output_available.size());
+
+ for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
+ {
+#ifdef OMX_USEBUFFER
+ uint8_t *buf = m_omx_output_buffers[i]->pBuffer;
+#endif
+ omx_err = OMX_FreeBuffer(m_handle, m_output_port, m_omx_output_buffers[i]);
+#ifdef OMX_USEBUFFER
+ if(buf)
+ _aligned_free(buf);
+#endif
+ //m_omx_output_buffers[i]->pBuffer = NULL;
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::FreeOutputBuffers error deallocate omx output buffer on component %s omx_err(0x%08x)\n", m_componentName.c_str(), omx_err);
+ }
+ }
+
+ m_omx_output_buffers.clear();
+
+ while (!m_omx_output_available.empty())
+ m_omx_output_available.pop();
+
+ m_output_alignment = 0;
+ m_output_buffer_size = 0;
+ m_output_buffer_count = 0;
+
+ pthread_mutex_unlock(&m_omx_output_mutex);
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::DisableAllPorts()
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ if(!m_handle)
+ {
+ UnLock();
+ return OMX_ErrorUndefined;
+ }
+
+ OMX_INDEXTYPE idxTypes[] = {
+ OMX_IndexParamAudioInit,
+ OMX_IndexParamImageInit,
+ OMX_IndexParamVideoInit,
+ OMX_IndexParamOtherInit
+ };
+
+ OMX_PORT_PARAM_TYPE ports;
+ OMX_INIT_STRUCTURE(ports);
+
+ int i;
+ for(i=0; i < 4; i++)
+ {
+ omx_err = OMX_GetParameter(m_handle, idxTypes[i], &ports);
+ if(omx_err == OMX_ErrorNone) {
+
+ uint32_t j;
+ for(j=0; j<ports.nPorts; j++)
+ {
+ omx_err = OMX_SendCommand(m_handle, OMX_CommandPortDisable, ports.nStartPortNumber+j, NULL);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::DisableAllPorts - Error disable port %d on component %s omx_err(0x%08x)",
+ (int)(ports.nStartPortNumber) + j, m_componentName.c_str(), (int)omx_err);
+ }
+ omx_err = WaitForCommand(OMX_CommandPortDisable, ports.nStartPortNumber+j);
+ if(omx_err != OMX_ErrorNone && omx_err != OMX_ErrorSameState)
+ {
+ UnLock();
+ return omx_err;
+ }
+ }
+ }
+ }
+
+ UnLock();
+
+ return OMX_ErrorNone;
+}
+
+void COMXCoreComponent::Remove(OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2)
+{
+ for (std::vector<omx_event>::iterator it = m_omx_events.begin(); it != m_omx_events.end(); it++) {
+ omx_event event = *it;
+
+ if(event.eEvent == eEvent && event.nData1 == nData1 && event.nData2 == nData2) {
+ m_omx_events.erase(it);
+ return;
+ }
+ }
+}
+
+OMX_ERRORTYPE COMXCoreComponent::AddEvent(OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2)
+{
+ omx_event event;
+
+ event.eEvent = eEvent;
+ event.nData1 = nData1;
+ event.nData2 = nData2;
+
+ pthread_mutex_lock(&m_omx_event_mutex);
+ Remove(eEvent, nData1, nData2);
+ m_omx_events.push_back(event);
+ // this allows (all) blocked tasks to be awoken
+ pthread_cond_broadcast(&m_omx_event_cond);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::AddEvent %s add event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+
+ return OMX_ErrorNone;
+}
+
+// timeout in milliseconds
+OMX_ERRORTYPE COMXCoreComponent::WaitForEvent(OMX_EVENTTYPE eventType, long timeout)
+{
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s wait event 0x%08x\n",
+ m_componentName.c_str(), (int)eventType);
+#endif
+
+ pthread_mutex_lock(&m_omx_event_mutex);
+ struct timespec endtime;
+ clock_gettime(CLOCK_REALTIME, &endtime);
+ add_timespecs(endtime, timeout);
+ while(true) {
+
+ for (std::vector<omx_event>::iterator it = m_omx_events.begin(); it != m_omx_events.end(); it++) {
+ omx_event event = *it;
+
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s inlist event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+
+
+ if(event.eEvent == OMX_EventError && event.nData1 == (OMX_U32)OMX_ErrorSameState && event.nData2 == 1)
+ {
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+ m_omx_events.erase(it);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorNone;
+ } else if(event.eEvent == OMX_EventError) {
+ m_omx_events.erase(it);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return (OMX_ERRORTYPE)event.nData1;
+ } else if(event.eEvent == eventType) {
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForEvent %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+
+ m_omx_events.erase(it);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorNone;
+ }
+ }
+
+ int retcode = pthread_cond_timedwait(&m_omx_event_cond, &m_omx_event_mutex, &endtime);
+ if (retcode != 0) {
+ CLog::Log(LOGERROR, "COMXCoreComponent::WaitForEvent %s wait event 0x%08x timeout %ld\n",
+ m_componentName.c_str(), (int)eventType, timeout);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorMax;
+ }
+ }
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorNone;
+}
+
+// timeout in milliseconds
+OMX_ERRORTYPE COMXCoreComponent::WaitForCommand(OMX_U32 command, OMX_U32 nData2, long timeout)
+{
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForCommand %s wait event.eEvent 0x%08x event.command 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)OMX_EventCmdComplete, (int)command, (int)nData2);
+#endif
+
+ pthread_mutex_lock(&m_omx_event_mutex);
+ struct timespec endtime;
+ clock_gettime(CLOCK_REALTIME, &endtime);
+ add_timespecs(endtime, timeout);
+ while(true) {
+
+ for (std::vector<omx_event>::iterator it = m_omx_events.begin(); it != m_omx_events.end(); it++) {
+ omx_event event = *it;
+
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForCommand %s inlist event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+ if(event.eEvent == OMX_EventError && event.nData1 == (OMX_U32)OMX_ErrorSameState && event.nData2 == 1)
+ {
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForCommand %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+
+ m_omx_events.erase(it);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorNone;
+ } else if(event.eEvent == OMX_EventError) {
+ m_omx_events.erase(it);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return (OMX_ERRORTYPE)event.nData1;
+ } else if(event.eEvent == OMX_EventCmdComplete && event.nData1 == command && event.nData2 == nData2) {
+
+#ifdef OMX_DEBUG_EVENTS
+ CLog::Log(LOGDEBUG, "COMXCoreComponent::WaitForCommand %s remove event event.eEvent 0x%08x event.nData1 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)event.eEvent, (int)event.nData1, (int)event.nData2);
+#endif
+
+ m_omx_events.erase(it);
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorNone;
+ }
+ }
+
+ int retcode = pthread_cond_timedwait(&m_omx_event_cond, &m_omx_event_mutex, &endtime);
+ if (retcode != 0) {
+ CLog::Log(LOGERROR, "COMXCoreComponent::WaitForCommand %s wait timeout event.eEvent 0x%08x event.command 0x%08x event.nData2 0x%08x\n",
+ m_componentName.c_str(), (int)OMX_EventCmdComplete, (int)command, (int)nData2);
+
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorMax;
+ }
+ }
+ pthread_mutex_unlock(&m_omx_event_mutex);
+ return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::SetStateForComponent(OMX_STATETYPE state)
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+ OMX_STATETYPE state_actual = OMX_StateMax;
+
+ if(!m_handle)
+ {
+ UnLock();
+ return OMX_ErrorUndefined;
+ }
+
+ OMX_GetState(m_handle, &state_actual);
+ if(state == state_actual)
+ {
+ UnLock();
+ return OMX_ErrorNone;
+ }
+
+ omx_err = OMX_SendCommand(m_handle, OMX_CommandStateSet, state, 0);
+ if (omx_err != OMX_ErrorNone)
+ {
+ if(omx_err == OMX_ErrorSameState)
+ {
+ omx_err = OMX_ErrorNone;
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::SetStateForComponent - %s failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+ }
+ else
+ {
+ omx_err = WaitForCommand(OMX_CommandStateSet, state);
+ if(omx_err == OMX_ErrorSameState)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::SetStateForComponent - %s ignore OMX_ErrorSameState\n",
+ m_componentName.c_str());
+ UnLock();
+ return OMX_ErrorNone;
+ }
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_STATETYPE COMXCoreComponent::GetState()
+{
+ Lock();
+
+ OMX_STATETYPE state;
+
+ if(m_handle)
+ {
+ OMX_GetState(m_handle, &state);
+ UnLock();
+ return state;
+ }
+
+ UnLock();
+
+ return (OMX_STATETYPE)0;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::SetParameter(OMX_INDEXTYPE paramIndex, OMX_PTR paramStruct)
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err;
+
+ omx_err = OMX_SetParameter(m_handle, paramIndex, paramStruct);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::SetParameter - %s failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::GetParameter(OMX_INDEXTYPE paramIndex, OMX_PTR paramStruct)
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err;
+
+ omx_err = OMX_GetParameter(m_handle, paramIndex, paramStruct);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::GetParameter - %s failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::SetConfig(OMX_INDEXTYPE configIndex, OMX_PTR configStruct)
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err;
+
+ omx_err = OMX_SetConfig(m_handle, configIndex, configStruct);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::SetConfig - %s failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::GetConfig(OMX_INDEXTYPE configIndex, OMX_PTR configStruct)
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err;
+
+ omx_err = OMX_GetConfig(m_handle, configIndex, configStruct);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::GetConfig - %s failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::SendCommand(OMX_COMMANDTYPE cmd, OMX_U32 cmdParam, OMX_PTR cmdParamData)
+{
+ Lock();
+
+ OMX_ERRORTYPE omx_err;
+
+ omx_err = OMX_SendCommand(m_handle, cmd, cmdParam, cmdParamData);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::SendCommand - %s failed with omx_err(0x%x)\n",
+ m_componentName.c_str(), omx_err);
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::EnablePort(unsigned int port, bool wait)
+{
+ Lock();
+
+ bool bEnabled = false;
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ for(int i = 0; i < OMX_MAX_PORTS; i++)
+ {
+ if(m_ports_enabled[i] == (int)port)
+ {
+ bEnabled = true;
+ break;
+ }
+ }
+
+ if(!bEnabled)
+ {
+ omx_err = OMX_SendCommand(m_handle, OMX_CommandPortEnable, port, NULL);
+ if(omx_err != OMX_ErrorNone)
+ {
+ CLog::Log(LOGERROR, "COMXCoreComponent::EnablePort - Error enable port %d on component %s omx_err(0x%08x)",
+ port, m_componentName.c_str(), (int)omx_err);
+ {
+ UnLock();
+ return omx_err;
+ }
+ }
+ else
+ {
+ if(wait)
+ omx_err = WaitForEvent(OMX_EventCmdComplete);
+
+ for(int i = 0; i < OMX_MAX_PORTS; i++)
+ {
+ if(m_ports_enabled[i] == -1)
+ {
+ m_ports_enabled[i] = (int)port;
+ break;
+ }
+ }
+ }
+ }
+
+ UnLock();
+
+ return omx_err;
+}
+
+OMX_ERRORTYPE COMXCoreComponent::DisablePort(unsigned int port, bool wait)
+{
+ Lock();
+
+ bool bEnabled = false;
+ OMX_ERRORTYPE omx_err = OMX_ErrorNone;
+
+ for(int i = 0; i < OMX_MAX_PORTS; i++)
+ {
+ if(m_ports_enabled[i] == (int)port)
+ {
+ bEnabled = true;