2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
23 #elif defined(TARGET_WINDOWS)
27 #if defined(HAVE_OMXLIB)
29 #include "video/VideoReferenceClock.h"
30 #include "settings/Settings.h"
33 #include "utils/MathUtils.h"
35 #define OMX_PRE_ROLL 200
36 #define TP(speed) ((speed) < 0 || (speed) > 4*DVD_PLAYSPEED_NORMAL)
43 m_omx_speed = DVD_PLAYSPEED_NORMAL;
45 m_eState = OMX_TIME_ClockStateStopped;
46 m_eClock = OMX_TIME_RefClockNone;
49 pthread_mutex_init(&m_lock, NULL);
55 pthread_mutex_destroy(&m_lock);
60 pthread_mutex_lock(&m_lock);
63 void OMXClock::UnLock()
65 pthread_mutex_unlock(&m_lock);
68 void OMXClock::OMXSetClockPorts(OMX_TIME_CONFIG_CLOCKSTATETYPE *clock, bool has_video, bool has_audio)
70 if(m_omx_clock.GetComponent() == NULL)
80 clock->nWaitMask |= OMX_CLOCKPORT0;
85 clock->nWaitMask |= OMX_CLOCKPORT1;
89 bool OMXClock::OMXSetReferenceClock(bool has_audio, bool lock /* = true */)
95 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
96 OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE refClock;
97 OMX_INIT_STRUCTURE(refClock);
100 refClock.eClock = OMX_TIME_RefClockAudio;
102 refClock.eClock = OMX_TIME_RefClockVideo;
104 if (refClock.eClock != m_eClock)
106 CLog::Log(LOGNOTICE, "OMXClock using %s as reference", refClock.eClock == OMX_TIME_RefClockVideo ? "video" : "audio");
108 omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeActiveRefClock, &refClock);
109 if(omx_err != OMX_ErrorNone)
111 CLog::Log(LOGERROR, "OMXClock::OMXSetReferenceClock error setting OMX_IndexConfigTimeActiveRefClock");
114 m_eClock = refClock.eClock;
122 bool OMXClock::OMXInitialize(CDVDClock *clock)
124 std::string componentName = "";
130 componentName = "OMX.broadcom.clock";
131 if(!m_omx_clock.Initialize((const std::string)componentName, OMX_IndexParamOtherInit))
134 m_omx_clock.DisableAllPorts();
139 void OMXClock::OMXDeinitialize()
141 if(m_omx_clock.GetComponent() == NULL)
144 m_omx_clock.Deinitialize();
146 m_omx_speed = DVD_PLAYSPEED_NORMAL;
149 bool OMXClock::OMXStateExecute(bool lock /* = true */)
151 if(m_omx_clock.GetComponent() == NULL)
157 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
159 if(m_omx_clock.GetState() != OMX_StateExecuting)
164 omx_err = m_omx_clock.SetStateForComponent(OMX_StateExecuting);
165 if (omx_err != OMX_ErrorNone)
167 CLog::Log(LOGERROR, "OMXClock::StateExecute m_omx_clock.SetStateForComponent\n");
180 void OMXClock::OMXStateIdle(bool lock /* = true */)
182 if(m_omx_clock.GetComponent() == NULL)
188 if(m_omx_clock.GetState() == OMX_StateExecuting)
189 m_omx_clock.SetStateForComponent(OMX_StatePause);
191 if(m_omx_clock.GetState() != OMX_StateIdle)
192 m_omx_clock.SetStateForComponent(OMX_StateIdle);
198 COMXCoreComponent *OMXClock::GetOMXClock()
203 bool OMXClock::OMXStop(bool lock /* = true */)
205 if(m_omx_clock.GetComponent() == NULL)
211 CLog::Log(LOGDEBUG, "OMXClock::OMXStop\n");
213 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
214 OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
215 OMX_INIT_STRUCTURE(clock);
217 clock.eState = OMX_TIME_ClockStateStopped;
218 clock.nOffset = ToOMXTime(-1000LL * OMX_PRE_ROLL);
220 omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
221 if(omx_err != OMX_ErrorNone)
223 CLog::Log(LOGERROR, "OMXClock::Stop error setting OMX_IndexConfigTimeClockState\n");
228 m_eState = clock.eState;
236 bool OMXClock::OMXStep(int steps /* = 1 */, bool lock /* = true */)
238 if(m_omx_clock.GetComponent() == NULL)
244 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
245 OMX_PARAM_U32TYPE param;
246 OMX_INIT_STRUCTURE(param);
248 param.nPortIndex = OMX_ALL;
251 omx_err = m_omx_clock.SetConfig(OMX_IndexConfigSingleStep, ¶m);
252 if(omx_err != OMX_ErrorNone)
254 CLog::Log(LOGERROR, "OMXClock::Error setting OMX_IndexConfigSingleStep\n");
263 CLog::Log(LOGDEBUG, "OMXClock::Step (%d)", steps);
267 bool OMXClock::OMXReset(bool has_video, bool has_audio, bool lock /* = true */)
269 if(m_omx_clock.GetComponent() == NULL)
275 if(!OMXSetReferenceClock(has_audio, false))
282 if (m_eState == OMX_TIME_ClockStateStopped)
284 OMX_TIME_CONFIG_CLOCKSTATETYPE clock;
285 OMX_INIT_STRUCTURE(clock);
287 clock.eState = OMX_TIME_ClockStateWaitingForStartTime;
288 clock.nOffset = ToOMXTime(-1000LL * OMX_PRE_ROLL);
290 OMXSetClockPorts(&clock, has_video, has_audio);
294 OMX_ERRORTYPE omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeClockState, &clock);
295 if(omx_err != OMX_ErrorNone)
297 CLog::Log(LOGERROR, "OMXClock::OMXReset error setting OMX_IndexConfigTimeClockState\n");
302 CLog::Log(LOGDEBUG, "OMXClock::OMXReset audio / video : %d / %d wait mask %d->%d state : %d->%d\n",
303 has_audio, has_video, m_WaitMask, clock.nWaitMask, m_eState, clock.eState);
304 if (m_eState != OMX_TIME_ClockStateStopped)
305 m_WaitMask = clock.nWaitMask;
306 m_eState = clock.eState;
316 double OMXClock::OMXMediaTime(bool lock /* = true */)
318 if(m_omx_clock.GetComponent() == NULL)
324 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
327 OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
328 OMX_INIT_STRUCTURE(timeStamp);
329 timeStamp.nPortIndex = m_omx_clock.GetInputPort();
331 omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
332 if(omx_err != OMX_ErrorNone)
334 CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime\n");
340 pts = FromOMXTime(timeStamp.nTimestamp);
348 double OMXClock::OMXClockAdjustment(bool lock /* = true */)
350 if(m_omx_clock.GetComponent() == NULL)
356 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
359 OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
360 OMX_INIT_STRUCTURE(timeStamp);
361 timeStamp.nPortIndex = m_omx_clock.GetInputPort();
363 omx_err = m_omx_clock.GetConfig(OMX_IndexConfigClockAdjustment, &timeStamp);
364 if(omx_err != OMX_ErrorNone)
366 CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigClockAdjustment\n");
372 pts = (double)FromOMXTime(timeStamp.nTimestamp);
373 //CLog::Log(LOGINFO, "OMXClock::ClockAdjustment %.0f %.0f\n", (double)FromOMXTime(timeStamp.nTimestamp), pts);
381 // Set the media time, so calls to get media time use the updated value,
382 // useful after a seek so mediatime is updated immediately (rather than waiting for first decoded packet)
383 bool OMXClock::OMXMediaTime(double pts, bool lock /* = true*/)
385 if(m_omx_clock.GetComponent() == NULL)
391 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
393 OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
394 OMX_INIT_STRUCTURE(timeStamp);
395 timeStamp.nPortIndex = m_omx_clock.GetInputPort();
397 if(m_eClock == OMX_TIME_RefClockAudio)
398 index = OMX_IndexConfigTimeCurrentAudioReference;
400 index = OMX_IndexConfigTimeCurrentVideoReference;
402 timeStamp.nTimestamp = ToOMXTime(pts);
404 omx_err = m_omx_clock.SetConfig(index, &timeStamp);
405 if(omx_err != OMX_ErrorNone)
407 CLog::Log(LOGERROR, "OMXClock::OMXMediaTime error setting %s", index == OMX_IndexConfigTimeCurrentAudioReference ?
408 "OMX_IndexConfigTimeCurrentAudioReference":"OMX_IndexConfigTimeCurrentVideoReference");
414 CLog::Log(LOGDEBUG, "OMXClock::OMXMediaTime set config %s = %.2f", index == OMX_IndexConfigTimeCurrentAudioReference ?
415 "OMX_IndexConfigTimeCurrentAudioReference":"OMX_IndexConfigTimeCurrentVideoReference", pts);
423 bool OMXClock::OMXPause(bool lock /* = true */)
425 if(m_omx_clock.GetComponent() == NULL)
433 if (OMXSetSpeed(0, false, true))
439 return m_pause == true;
442 bool OMXClock::OMXResume(bool lock /* = true */)
444 if(m_omx_clock.GetComponent() == NULL)
452 if (OMXSetSpeed(m_omx_speed, false, true))
458 return m_pause == false;
461 bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume /* = false */)
463 if(m_omx_clock.GetComponent() == NULL)
469 CLog::Log(LOGDEBUG, "OMXClock::OMXSetSpeed(%.2f) pause_resume:%d", (float)speed / (float)DVD_PLAYSPEED_NORMAL, pause_resume);
473 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
474 OMX_TIME_CONFIG_SCALETYPE scaleType;
475 OMX_INIT_STRUCTURE(scaleType);
478 scaleType.xScale = 0; // for trickplay we just pause, and single step
480 scaleType.xScale = (speed << 16) / DVD_PLAYSPEED_NORMAL;
481 omx_err = m_omx_clock.SetConfig(OMX_IndexConfigTimeScale, &scaleType);
482 if(omx_err != OMX_ErrorNone)
484 CLog::Log(LOGERROR, "OMXClock::OMXSetSpeed error setting OMX_IndexConfigTimeClockState\n");
499 bool OMXClock::HDMIClockSync(bool lock /* = true */)
501 if(m_omx_clock.GetComponent() == NULL)
507 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
508 OMX_CONFIG_LATENCYTARGETTYPE latencyTarget;
509 OMX_INIT_STRUCTURE(latencyTarget);
511 latencyTarget.nPortIndex = OMX_ALL;
512 latencyTarget.bEnabled = OMX_TRUE;
513 latencyTarget.nFilter = 10;
514 latencyTarget.nTarget = 0;
515 latencyTarget.nShift = 3;
516 latencyTarget.nSpeedFactor = -200;
517 latencyTarget.nInterFactor = 100;
518 latencyTarget.nAdjCap = 100;
520 omx_err = m_omx_clock.SetConfig(OMX_IndexConfigLatencyTarget, &latencyTarget);
521 if(omx_err != OMX_ErrorNone)
523 CLog::Log(LOGERROR, "OMXClock::Speed error setting OMX_IndexConfigLatencyTarget\n");
535 int64_t OMXClock::CurrentHostCounter(void)
538 clock_gettime(CLOCK_MONOTONIC, &now);
539 return( ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec );
542 int64_t OMXClock::CurrentHostFrequency(void)
544 return( (int64_t)1000000000L );
547 int OMXClock::GetRefreshRate(double* interval)
556 double OMXClock::NormalizeFrameduration(double frameduration)
558 //if the duration is within 20 microseconds of a common duration, use that
559 const double durations[] = {DVD_TIME_BASE * 1.001 / 24.0, DVD_TIME_BASE / 24.0, DVD_TIME_BASE / 25.0,
560 DVD_TIME_BASE * 1.001 / 30.0, DVD_TIME_BASE / 30.0, DVD_TIME_BASE / 50.0,
561 DVD_TIME_BASE * 1.001 / 60.0, DVD_TIME_BASE / 60.0};
563 double lowestdiff = DVD_TIME_BASE;
565 for (size_t i = 0; i < sizeof(durations) / sizeof(durations[0]); i++)
567 double diff = fabs(frameduration - durations[i]);
568 if (diff < DVD_MSEC_TO_TIME(0.02) && diff < lowestdiff)
576 return durations[selected];
578 return frameduration;