summaryrefslogtreecommitdiff
path: root/tools/time_pts.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/time_pts.c')
-rw-r--r--tools/time_pts.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/tools/time_pts.c b/tools/time_pts.c
new file mode 100644
index 00000000..077a9a17
--- /dev/null
+++ b/tools/time_pts.c
@@ -0,0 +1,154 @@
+/*
+ * time_pts.c: Adjustable clock in PTS units
+ *
+ * See the main source file 'xineliboutput.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: time_pts.c,v 1.1 2007-01-06 03:42:17 phintuka Exp $
+ *
+ */
+
+#define __STDC_FORMAT_MACROS
+#define __STDC_CONSTANT_MACROS
+#include <inttypes.h>
+#include <time.h>
+
+#include <vdr/config.h>
+
+#include "../logdefs.h" // logging
+
+#include "time_pts.h"
+
+
+#define MAX_SCR ((int64_t)0x1ffffffffLL)
+
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
+#else
+# warning Posix monotonic clock not available
+#endif
+
+
+cTimePts::cTimePts(void)
+{
+ m_Paused = false;
+ m_Multiplier = 90000;
+ m_Monotonic = false;
+
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
+ struct timespec resolution;
+
+ if(clock_getres(CLOCK_MONOTONIC, &resolution)) {
+ LOGERR("cTimePts: clock_getres(CLOCK_MONOTONIC) failed");
+ } else {
+ LOGDBG("cTimePts: clock_gettime(CLOCK_MONOTONIC): clock resolution %d us",
+ ((int)resolution.tv_nsec) / 1000);
+
+ if( resolution.tv_sec == 0 && resolution.tv_nsec <= 1000000 ) {
+ struct timespec tp;
+ if(clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ LOGERR("cTimePts: clock_gettime(CLOCL_MONOTONIC) failed");
+ } else {
+ LOGDBG("cTimePts: using monotonic clock");
+ m_Monotonic = true;
+ }
+ }
+ }
+#endif
+
+ Set();
+}
+
+int64_t cTimePts::Now(void)
+{
+ if(m_Paused)
+ return begin;
+
+ struct timeval t;
+
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
+ if(m_Monotonic) {
+ struct timespec tp;
+
+ if(clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ LOGERR("cTimePts: clock_gettime(CLOCK_MONOTONIC) failed");
+ return -1;
+ }
+
+ t.tv_sec = tp.tv_sec;
+ t.tv_usec = tp.tv_nsec/1000;
+
+ } else if (gettimeofday(&t, NULL)) {
+ LOGERR("cTimePts: gettimeofday() failed");
+ return -1;
+ }
+#else
+ if (gettimeofday(&t, NULL)) {
+ LOGERR("cTimePts: gettimeofday() failed");
+ return -1;
+ }
+#endif
+
+ t.tv_sec -= tbegin.tv_sec;
+ if(t.tv_usec < tbegin.tv_usec) {
+ t.tv_sec--;
+ t.tv_usec += 1000000;
+ }
+ t.tv_usec -= tbegin.tv_usec;
+
+ int64_t pts = 0;
+ pts += ((int64_t)t.tv_sec) * INT64_C(90000);
+ pts += ((int64_t)t.tv_usec) * INT64_C(90) / INT64_C(1000);
+ if(m_Multiplier != 90000)
+ pts = pts * m_Multiplier / INT64_C(90000);
+
+ return ( pts + begin ) & MAX_SCR;
+}
+
+void cTimePts::Set(int64_t Pts)
+{
+ begin = Pts;
+
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK)
+ if(m_Monotonic) {
+ struct timespec tp;
+
+ if(!clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ tbegin.tv_sec = tp.tv_sec;
+ tbegin.tv_usec = tp.tv_nsec/1000;
+ return;
+ }
+
+ LOGERR("cTimePts: clock_gettime(CLOCL_MONOTONIC) failed");
+ m_Monotonic = false;
+ }
+#endif
+
+ gettimeofday(&tbegin, NULL);
+}
+
+void cTimePts::Pause(void)
+{
+ Set(Now());
+ m_Paused = true;
+}
+
+void cTimePts::Resume(void)
+{
+ if(m_Paused) {
+ Set(begin);
+ m_Paused = false;
+ }
+}
+
+void cTimePts::TrickSpeed(int Multiplier)
+{
+ Set(Now());
+
+ if(Multiplier < 0)
+ m_Multiplier = 90000 * (-Multiplier);
+ else if(Multiplier > 0)
+ m_Multiplier = 90000 / Multiplier;
+ else
+ LOGERR("cTimePts::SetSpeed: Multiplier=%d", Multiplier);
+}
+