mtime.c 5.89 KB
Newer Older
1
/*****************************************************************************
2
 * mtime.c: high resolution time management functions
Clément Stenac's avatar
Clément Stenac committed
3
 * Functions are prototyped in vlc_mtime.h.
4
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
5
 * Copyright (C) 1998-2007 VLC authors and VideoLAN
6
 * Copyright © 2006-2007 Rémi Denis-Courmont
7
 * $Id$
8
 *
9
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
10
 *          Rémi Denis-Courmont <rem$videolan,org>
11
 *          Gisle Vanem
12
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
13 14 15
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
16
 * (at your option) any later version.
17
 *
18 19
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
20 21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
22
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
23 24 25
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
27

28
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
29
 * Preamble
30
 *****************************************************************************/
31

32 33 34 35
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

36
#include <vlc_common.h>
37
#include <assert.h>
38

39
#include <time.h>
40

Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
41 42 43
/**
 * Convert seconds to a time in the format h:mm:ss.
 *
44 45 46 47 48 49 50
 * This function is provided for any interface function which need to print a
 * time string in the format h:mm:ss
 * date.
 * \param secs  the 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.
 */
51
char *secstotimestr( char *psz_buffer, int32_t i_seconds )
52
{
53 54 55 56 57 58 59
    if( unlikely(i_seconds < 0) )
    {
        secstotimestr( psz_buffer + 1, -i_seconds );
        *psz_buffer = '-';
        return psz_buffer;
    }

60 61 62 63 64 65 66
    div_t d;

    d = div( i_seconds, 60 );
    i_seconds = d.rem;
    d = div( d.quot, 60 );

    if( d.quot )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
67
        snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%u:%02u:%02u",
68
                 d.quot, d.rem, i_seconds );
69
    else
70 71
        snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02u:%02u",
                  d.rem, i_seconds );
72
    return psz_buffer;
73 74
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
/*
 * 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 )
{
105 106
    /* change time scale of remainder */
    p_date->i_remainder = p_date->i_remainder * i_divider_n / p_date->i_divider_num;
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    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 )
{
155 156 157 158 159
    mtime_t i_dividend = i_nb_samples * CLOCK_FREQ * p_date->i_divider_den;
    lldiv_t d = lldiv( i_dividend, p_date->i_divider_num );

    p_date->date += d.quot;
    p_date->i_remainder += (int)d.rem;
160 161 162 163

    if( p_date->i_remainder >= p_date->i_divider_num )
    {
        /* This is Bresenham algorithm. */
164
        assert( p_date->i_remainder < 2*p_date->i_divider_num);
165
        p_date->date += 1;
166 167 168 169 170
        p_date->i_remainder -= p_date->i_divider_num;
    }

    return p_date->date;
}
171

172 173 174 175 176 177 178 179 180 181
/**
 * Decrement the date and return the result, taking into account
 * rounding errors.
 *
 * \param date to decrement
 * \param decrementation in number of samples
 * \return date value
 */
mtime_t date_Decrement( date_t *p_date, uint32_t i_nb_samples )
{
182
    mtime_t i_dividend = (mtime_t)i_nb_samples * CLOCK_FREQ * p_date->i_divider_den;
183 184 185 186 187 188
    p_date->date -= i_dividend / p_date->i_divider_num;
    unsigned i_rem_adjust = i_dividend % p_date->i_divider_num;

    if( p_date->i_remainder < i_rem_adjust )
    {
        /* This is Bresenham algorithm. */
189
        assert( p_date->i_remainder < p_date->i_divider_num);
190 191 192 193 194 195 196 197 198
        p_date->date -= 1;
        p_date->i_remainder += p_date->i_divider_num;
    }

    p_date->i_remainder -= i_rem_adjust;

    return p_date->date;
}

199 200 201
/**
 * @return NTP 64-bits timestamp in host byte order.
 */
202
uint64_t NTPtime64(void)
203 204
{
    struct timespec ts;
205

206
    timespec_get(&ts, TIME_UTC);
207 208 209 210 211

    /* Convert nanoseconds to 32-bits fraction (232 picosecond units) */
    uint64_t t = (uint64_t)(ts.tv_nsec) << 32;
    t /= 1000000000;

212 213
    /* The offset to Unix epoch is 70 years (incl. 17 leap ones). There were
     * no leap seconds during that period since they had not been invented yet.
214
     */
215
    t |= ((UINT64_C(70) * 365 + 17) * 24 * 60 * 60 + ts.tv_sec) << 32;
216 217
    return t;
}