]> git.sesse.net Git - vlc/blobdiff - src/misc/mtime.c
* src/misc/mtime.c, include/mtime.h: new common "date" API for date incrementation...
[vlc] / src / misc / mtime.c
index 324feea0705357fca0840a1b4d3ce7779881ac95..4f2bcaa75fb40cda7bedcbcbf105f362baa3c3a6 100644 (file)
@@ -2,8 +2,8 @@
  * mtime.c: high resolution time management functions
  * Functions are prototyped in mtime.h.
  *****************************************************************************
- * Copyright (C) 1998-2001, 2003 VideoLAN
- * $Id: mtime.c,v 1.39 2003/12/03 21:50:50 sigmunau Exp $
+ * Copyright (C) 1998-2004 VideoLAN
+ * $Id$
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
@@ -11,7 +11,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, 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
@@ -69,7 +69,7 @@ int nanosleep(struct timespec *, struct timespec *);
  *
  * This function converts a mtime date into a string.
  * psz_buffer should be a buffer long enough to store the formatted
- * date. 
+ * date.
  * \param date to be converted
  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
  * \return psz_buffer is returned so this can be used as printf parameter.
@@ -100,8 +100,8 @@ char *mstrtime( char *psz_buffer, mtime_t date )
 char *secstotimestr( char *psz_buffer, int i_seconds )
 {
     snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%d:%2.2d:%2.2d",
-              (int) (i_seconds / (60 *60)), 
-              (int) ((i_seconds / 60) % 60), 
+              (int) (i_seconds / (60 *60)),
+              (int) ((i_seconds / 60) % 60),
               (int) (i_seconds % 60) );
     return( psz_buffer );
 }
@@ -154,9 +154,39 @@ mtime_t mdate( void )
         QueryPerformanceCounter( (LARGE_INTEGER *)&usec_time );
         return ( usec_time * 1000000 ) / freq;
     }
-
-    /* Milisecond resolution (actually, best case is about 10 ms resolution) */
-    return 1000 * GetTickCount();
+    else
+    {
+        /* Fallback on GetTickCount() which has a milisecond resolution
+         * (actually, best case is about 10 ms resolution)
+         * GetTickCount() only returns a DWORD thus will wrap after
+         * about 49.7 days so we try to detect the wrapping. */
+
+        static CRITICAL_SECTION date_lock;
+        static mtime_t i_previous_time = I64C(-1);
+        static int i_wrap_counts = -1;
+
+        if( i_wrap_counts == -1 )
+        {
+            /* Initialization */
+            i_previous_time = I64C(1000) * GetTickCount();
+            InitializeCriticalSection( &date_lock );
+            i_wrap_counts = 0;
+        }
+
+        EnterCriticalSection( &date_lock );
+        usec_time = I64C(1000) *
+            (i_wrap_counts * I64C(0x100000000) + GetTickCount());
+        if( i_previous_time > usec_time )
+        {
+            /* Counter wrapped */
+            i_wrap_counts++;
+            usec_time += I64C(0x100000000000);
+        }
+        i_previous_time = usec_time;
+        LeaveCriticalSection( &date_lock );
+
+        return usec_time;
+    }
 
 #else
     struct timeval tv_date;
@@ -182,7 +212,7 @@ void mwait( mtime_t date )
 {
 #if defined( HAVE_KERNEL_OS_H )
     mtime_t delay;
-    
+
     delay = date - real_time_clock_usecs();
     if( delay <= 0 )
     {
@@ -293,3 +323,94 @@ void msleep( mtime_t delay )
 #endif
 }
 
+/*
+ * Date management (internal and external)
+ */
+
+/**
+ * Initialize a date_t.
+ *
+ * \param date to initialize
+ * \param divider (sample rate) numerator
+ * \param divider (sample rate) denominator
+ */
+
+void date_Init( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
+{
+    p_date->date = 0;
+    p_date->i_divider_num = i_divider_n;
+    p_date->i_divider_den = i_divider_d;
+    p_date->i_remainder = 0;
+}
+
+/**
+ * Change a date_t.
+ *
+ * \param date to change
+ * \param divider (sample rate) numerator
+ * \param divider (sample rate) denominator
+ */
+
+void date_Change( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
+{
+    p_date->i_divider_num = i_divider_n;
+    p_date->i_divider_den = i_divider_d;
+}
+
+/**
+ * Set the date value of a date_t.
+ *
+ * \param date to set
+ * \param date value
+ */
+void date_Set( date_t *p_date, mtime_t i_new_date )
+{
+    p_date->date = i_new_date;
+    p_date->i_remainder = 0;
+}
+
+/**
+ * Get the date of a date_t
+ *
+ * \param date to get
+ * \return date value
+ */
+mtime_t date_Get( const date_t *p_date )
+{
+    return p_date->date;
+}
+
+/**
+ * Move forwards or backwards the date of a date_t.
+ *
+ * \param date to move
+ * \param difference value
+ */
+void date_Move( date_t *p_date, mtime_t i_difference )
+{
+    p_date->date += i_difference;
+}
+
+/**
+ * Increment the date and return the result, taking into account
+ * rounding errors.
+ *
+ * \param date to increment
+ * \param incrementation in number of samples
+ * \return date value
+ */
+mtime_t date_Increment( date_t *p_date, uint32_t i_nb_samples )
+{
+    mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000;
+    p_date->date += i_dividend / p_date->i_divider_num * p_date->i_divider_den;
+    p_date->i_remainder += (int)(i_dividend % p_date->i_divider_num);
+
+    if( p_date->i_remainder >= p_date->i_divider_num )
+    {
+        /* This is Bresenham algorithm. */
+        p_date->date += p_date->i_divider_den;
+        p_date->i_remainder -= p_date->i_divider_num;
+    }
+
+    return p_date->date;
+}