mtime.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:12k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * mtime.c: high resolution time management functions
  3.  * Functions are prototyped in mtime.h.
  4.  *****************************************************************************
  5.  * Copyright (C) 1998-2004 VideoLAN
  6.  * $Id: mtime.c 8165 2004-07-10 18:08:09Z gbazin $
  7.  *
  8.  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  23.  *****************************************************************************/
  24. /*
  25.  * TODO:
  26.  *  see if using Linux real-time extensions is possible and profitable
  27.  */
  28. /*****************************************************************************
  29.  * Preamble
  30.  *****************************************************************************/
  31. #include <stdio.h>                                              /* sprintf() */
  32. #include <vlc/vlc.h>
  33. #if defined( PTH_INIT_IN_PTH_H )                                  /* GNU Pth */
  34. #   include <pth.h>
  35. #endif
  36. #ifdef HAVE_UNISTD_H
  37. #   include <unistd.h>                                           /* select() */
  38. #endif
  39. #ifdef HAVE_KERNEL_OS_H
  40. #   include <kernel/OS.h>
  41. #endif
  42. #if defined( WIN32 ) || defined( UNDER_CE )
  43. #   include <windows.h>
  44. #else
  45. #   include <sys/time.h>
  46. #endif
  47. #if defined(HAVE_NANOSLEEP) && !defined(HAVE_STRUCT_TIMESPEC)
  48. struct timespec
  49. {
  50.     time_t  tv_sec;
  51.     int32_t tv_nsec;
  52. };
  53. #endif
  54. #if defined(HAVE_NANOSLEEP) && !defined(HAVE_DECL_NANOSLEEP)
  55. int nanosleep(struct timespec *, struct timespec *);
  56. #endif
  57. /**
  58.  * Return a date in a readable format
  59.  *
  60.  * This function converts a mtime date into a string.
  61.  * psz_buffer should be a buffer long enough to store the formatted
  62.  * date.
  63.  * param date to be converted
  64.  * param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
  65.  * return psz_buffer is returned so this can be used as printf parameter.
  66.  */
  67. char *mstrtime( char *psz_buffer, mtime_t date )
  68. {
  69.     static mtime_t ll1000 = 1000, ll60 = 60, ll24 = 24;
  70.     snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02d:%02d:%02d-%03d.%03d",
  71.              (int) (date / (ll1000 * ll1000 * ll60 * ll60) % ll24),
  72.              (int) (date / (ll1000 * ll1000 * ll60) % ll60),
  73.              (int) (date / (ll1000 * ll1000) % ll60),
  74.              (int) (date / ll1000 % ll1000),
  75.              (int) (date % ll1000) );
  76.     return( psz_buffer );
  77. }
  78. /**
  79.  * Convert seconds to a time in the format h:mm:ss.
  80.  *
  81.  * This function is provided for any interface function which need to print a
  82.  * time string in the format h:mm:ss
  83.  * date.
  84.  * param secs  the date to be converted
  85.  * param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
  86.  * return psz_buffer is returned so this can be used as printf parameter.
  87.  */
  88. char *secstotimestr( char *psz_buffer, int i_seconds )
  89. {
  90.     snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%d:%2.2d:%2.2d",
  91.               (int) (i_seconds / (60 *60)),
  92.               (int) ((i_seconds / 60) % 60),
  93.               (int) (i_seconds % 60) );
  94.     return( psz_buffer );
  95. }
  96. /**
  97.  * Return high precision date
  98.  *
  99.  * Uses the gettimeofday() function when possible (1 MHz resolution) or the
  100.  * ftime() function (1 kHz resolution).
  101.  */
  102. mtime_t mdate( void )
  103. {
  104. #if defined( HAVE_KERNEL_OS_H )
  105.     return( real_time_clock_usecs() );
  106. #elif defined( WIN32 ) || defined( UNDER_CE )
  107.     /* We don't need the real date, just the value of a high precision timer */
  108.     static mtime_t freq = I64C(-1);
  109.     mtime_t usec_time;
  110.     if( freq == I64C(-1) )
  111.     {
  112.         /* Extract from the Tcl source code:
  113.          * (http://www.cs.man.ac.uk/fellowsd-bin/TIP/7.html)
  114.          *
  115.          * Some hardware abstraction layers use the CPU clock
  116.          * in place of the real-time clock as a performance counter
  117.          * reference.  This results in:
  118.          *    - inconsistent results among the processors on
  119.          *      multi-processor systems.
  120.          *    - unpredictable changes in performance counter frequency
  121.          *      on "gearshift" processors such as Transmeta and
  122.          *      SpeedStep.
  123.          * There seems to be no way to test whether the performance
  124.          * counter is reliable, but a useful heuristic is that
  125.          * if its frequency is 1.193182 MHz or 3.579545 MHz, it's
  126.          * derived from a colorburst crystal and is therefore
  127.          * the RTC rather than the TSC.  If it's anything else, we
  128.          * presume that the performance counter is unreliable.
  129.          */
  130.         freq = ( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) &&
  131.                  (freq == I64C(1193182) || freq == I64C(3579545) ) )
  132.                ? freq : 0;
  133.     }
  134.     if( freq != 0 )
  135.     {
  136.         /* Microsecond resolution */
  137.         QueryPerformanceCounter( (LARGE_INTEGER *)&usec_time );
  138.         return ( usec_time * 1000000 ) / freq;
  139.     }
  140.     else
  141.     {
  142.         /* Fallback on GetTickCount() which has a milisecond resolution
  143.          * (actually, best case is about 10 ms resolution)
  144.          * GetTickCount() only returns a DWORD thus will wrap after
  145.          * about 49.7 days so we try to detect the wrapping. */
  146.         static CRITICAL_SECTION date_lock;
  147.         static mtime_t i_previous_time = I64C(-1);
  148.         static int i_wrap_counts = -1;
  149.         if( i_wrap_counts == -1 )
  150.         {
  151.             /* Initialization */
  152.             i_previous_time = I64C(1000) * GetTickCount();
  153.             InitializeCriticalSection( &date_lock );
  154.             i_wrap_counts = 0;
  155.         }
  156.         EnterCriticalSection( &date_lock );
  157.         usec_time = I64C(1000) *
  158.             (i_wrap_counts * I64C(0x100000000) + GetTickCount());
  159.         if( i_previous_time > usec_time )
  160.         {
  161.             /* Counter wrapped */
  162.             i_wrap_counts++;
  163.             usec_time += I64C(0x100000000000);
  164.         }
  165.         i_previous_time = usec_time;
  166.         LeaveCriticalSection( &date_lock );
  167.         return usec_time;
  168.     }
  169. #else
  170.     struct timeval tv_date;
  171.     /* gettimeofday() could return an error, and should be tested. However, the
  172.      * only possible error, according to 'man', is EFAULT, which can not happen
  173.      * here, since tv is a local variable. */
  174.     gettimeofday( &tv_date, NULL );
  175.     return( (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec );
  176. #endif
  177. }
  178. /**
  179.  * Wait for a date
  180.  *
  181.  * This function uses select() and an system date function to wake up at a
  182.  * precise date. It should be used for process synchronization. If current date
  183.  * is posterior to wished date, the function returns immediately.
  184.  * param date The date to wake up at
  185.  */
  186. void mwait( mtime_t date )
  187. {
  188. #if defined( HAVE_KERNEL_OS_H )
  189.     mtime_t delay;
  190.     delay = date - real_time_clock_usecs();
  191.     if( delay <= 0 )
  192.     {
  193.         return;
  194.     }
  195.     snooze( delay );
  196. #elif defined( WIN32 ) || defined( UNDER_CE )
  197.     mtime_t usec_time, delay;
  198.     usec_time = mdate();
  199.     delay = date - usec_time;
  200.     if( delay <= 0 )
  201.     {
  202.         return;
  203.     }
  204.     msleep( delay );
  205. #else
  206.     struct timeval tv_date;
  207.     mtime_t        delay;          /* delay in msec, signed to detect errors */
  208.     /* see mdate() about gettimeofday() possible errors */
  209.     gettimeofday( &tv_date, NULL );
  210.     /* calculate delay and check if current date is before wished date */
  211.     delay = date - (mtime_t) tv_date.tv_sec * 1000000
  212.                  - (mtime_t) tv_date.tv_usec
  213.                  - 10000;
  214.     /* Linux/i386 has a granularity of 10 ms. It's better to be in advance
  215.      * than to be late. */
  216.     if( delay <= 0 )                 /* wished date is now or already passed */
  217.     {
  218.         return;
  219.     }
  220. #   if defined( PTH_INIT_IN_PTH_H )
  221.     pth_usleep( delay );
  222. #   elif defined( ST_INIT_IN_ST_H )
  223.     st_usleep( delay );
  224. #   else
  225. #       if defined( HAVE_NANOSLEEP )
  226.     {
  227.         struct timespec ts_delay;
  228.         ts_delay.tv_sec = delay / 1000000;
  229.         ts_delay.tv_nsec = (delay % 1000000) * 1000;
  230.         nanosleep( &ts_delay, NULL );
  231.     }
  232. #       else
  233.     tv_date.tv_sec = delay / 1000000;
  234.     tv_date.tv_usec = delay % 1000000;
  235.     /* see msleep() about select() errors */
  236.     select( 0, NULL, NULL, NULL, &tv_date );
  237. #       endif
  238. #   endif
  239. #endif
  240. }
  241. /**
  242.  * More precise sleep()
  243.  *
  244.  * Portable usleep() function.
  245.  * param delay the amount of time to sleep
  246.  */
  247. void msleep( mtime_t delay )
  248. {
  249. #if defined( HAVE_KERNEL_OS_H )
  250.     snooze( delay );
  251. #elif defined( PTH_INIT_IN_PTH_H )
  252.     pth_usleep( delay );
  253. #elif defined( ST_INIT_IN_ST_H )
  254.     st_usleep( delay );
  255. #elif defined( WIN32 ) || defined( UNDER_CE )
  256.     Sleep( (int) (delay / 1000) );
  257. #elif defined( HAVE_NANOSLEEP )
  258.     struct timespec ts_delay;
  259.     ts_delay.tv_sec = delay / 1000000;
  260.     ts_delay.tv_nsec = (delay % 1000000) * 1000;
  261.     nanosleep( &ts_delay, NULL );
  262. #else
  263.     struct timeval tv_delay;
  264.     tv_delay.tv_sec = delay / 1000000;
  265.     tv_delay.tv_usec = delay % 1000000;
  266.     /* select() return value should be tested, since several possible errors
  267.      * can occur. However, they should only happen in very particular occasions
  268.      * (i.e. when a signal is sent to the thread, or when memory is full), and
  269.      * can be ignored. */
  270.     select( 0, NULL, NULL, NULL, &tv_delay );
  271. #endif
  272. }
  273. /*
  274.  * Date management (internal and external)
  275.  */
  276. /**
  277.  * Initialize a date_t.
  278.  *
  279.  * param date to initialize
  280.  * param divider (sample rate) numerator
  281.  * param divider (sample rate) denominator
  282.  */
  283. void date_Init( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
  284. {
  285.     p_date->date = 0;
  286.     p_date->i_divider_num = i_divider_n;
  287.     p_date->i_divider_den = i_divider_d;
  288.     p_date->i_remainder = 0;
  289. }
  290. /**
  291.  * Change a date_t.
  292.  *
  293.  * param date to change
  294.  * param divider (sample rate) numerator
  295.  * param divider (sample rate) denominator
  296.  */
  297. void date_Change( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
  298. {
  299.     p_date->i_divider_num = i_divider_n;
  300.     p_date->i_divider_den = i_divider_d;
  301. }
  302. /**
  303.  * Set the date value of a date_t.
  304.  *
  305.  * param date to set
  306.  * param date value
  307.  */
  308. void date_Set( date_t *p_date, mtime_t i_new_date )
  309. {
  310.     p_date->date = i_new_date;
  311.     p_date->i_remainder = 0;
  312. }
  313. /**
  314.  * Get the date of a date_t
  315.  *
  316.  * param date to get
  317.  * return date value
  318.  */
  319. mtime_t date_Get( const date_t *p_date )
  320. {
  321.     return p_date->date;
  322. }
  323. /**
  324.  * Move forwards or backwards the date of a date_t.
  325.  *
  326.  * param date to move
  327.  * param difference value
  328.  */
  329. void date_Move( date_t *p_date, mtime_t i_difference )
  330. {
  331.     p_date->date += i_difference;
  332. }
  333. /**
  334.  * Increment the date and return the result, taking into account
  335.  * rounding errors.
  336.  *
  337.  * param date to increment
  338.  * param incrementation in number of samples
  339.  * return date value
  340.  */
  341. mtime_t date_Increment( date_t *p_date, uint32_t i_nb_samples )
  342. {
  343.     mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000;
  344.     p_date->date += i_dividend / p_date->i_divider_num * p_date->i_divider_den;
  345.     p_date->i_remainder += (int)(i_dividend % p_date->i_divider_num);
  346.     if( p_date->i_remainder >= p_date->i_divider_num )
  347.     {
  348.         /* This is Bresenham algorithm. */
  349.         p_date->date += p_date->i_divider_den;
  350.         p_date->i_remainder -= p_date->i_divider_num;
  351.     }
  352.     return p_date->date;
  353. }