mirror of
https://github.com/mpv-player/mpv
synced 2025-01-13 00:06:25 +01:00
timer: refactor, add 64 bit timer function
Make OS specific timer code export a mp_raw_time_us() function, and add generic implementations of GetTimer()/GetTimerMS() using this function. New mpv code is supposed to call mp_time_us() in situations where precision is absolutely needed, or mp_time_s() otherwise. Make it so that mp_time_us() will return a value near program start. We don't set it to 0 though to avoid confusion with relative vs. absolute time. Instead, pick an arbitrary offset. Move the test program in timer-darwin.c to timer.c, and modify it to work with the generic timer functions.
This commit is contained in:
parent
25d66f526e
commit
81439c5f35
3
Makefile
3
Makefile
@ -215,8 +215,9 @@ SOURCES = talloc.c \
|
||||
demux/extension.c \
|
||||
demux/mf.c \
|
||||
demux/video.c \
|
||||
osdep/numcores.c \
|
||||
osdep/io.c \
|
||||
osdep/numcores.c \
|
||||
osdep/timer.c \
|
||||
stream/stream.c \
|
||||
stream/stream_avdevice.c \
|
||||
stream/stream_file.c \
|
||||
|
@ -4722,19 +4722,16 @@ static void osdep_preinit(int *p_argc, char ***p_argv)
|
||||
atexit(detach_ptw32);
|
||||
#endif
|
||||
|
||||
InitTimer();
|
||||
srand(GetTimerMS());
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
// stop Windows from showing all kinds of annoying error dialogs
|
||||
SetErrorMode(0x8003);
|
||||
// request 1ms timer resolution
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMCAP
|
||||
load_termcap(NULL); // load key-codes
|
||||
#endif
|
||||
|
||||
mp_time_init();
|
||||
}
|
||||
|
||||
/* This preprocessor directive is a hack to generate a mplayer-nomain.o object
|
||||
|
@ -27,72 +27,24 @@
|
||||
#include "core/mp_msg.h"
|
||||
#include "timer.h"
|
||||
|
||||
/* global variables */
|
||||
static double timebase_ratio;
|
||||
|
||||
|
||||
/* the core sleep function, uses floats and is used in MPlayer G2 */
|
||||
static float sleep_accurate(float time_frame)
|
||||
void mp_sleep_us(int64_t us)
|
||||
{
|
||||
uint64_t deadline = time_frame / timebase_ratio + mach_absolute_time();
|
||||
uint64_t deadline = us / 1e6 / timebase_ratio + mach_absolute_time();
|
||||
|
||||
mach_wait_until(deadline);
|
||||
|
||||
return (mach_absolute_time() - deadline) * timebase_ratio;
|
||||
mach_wait_until(deadline);
|
||||
}
|
||||
|
||||
/* wrapper for MPlayer G1 */
|
||||
int usec_sleep(int usec_delay)
|
||||
uint64_t mp_raw_time_us(void)
|
||||
{
|
||||
return sleep_accurate(usec_delay / 1e6) * 1e6;
|
||||
return mach_absolute_time() * timebase_ratio * 1e6;
|
||||
}
|
||||
|
||||
|
||||
/* current time in microseconds */
|
||||
unsigned int GetTimer(void)
|
||||
void mp_raw_time_init(void)
|
||||
{
|
||||
return (unsigned int)(uint64_t)(mach_absolute_time() * timebase_ratio * 1e6);
|
||||
struct mach_timebase_info timebase;
|
||||
|
||||
mach_timebase_info(&timebase);
|
||||
timebase_ratio = (double)timebase.numer / (double)timebase.denom * 1e-9;
|
||||
}
|
||||
|
||||
/* current time in milliseconds */
|
||||
unsigned int GetTimerMS(void)
|
||||
{
|
||||
return (unsigned int)(uint64_t)(mach_absolute_time() * timebase_ratio * 1e3);
|
||||
}
|
||||
|
||||
/* initialize timer, must be called at least once at start */
|
||||
void InitTimer(void)
|
||||
{
|
||||
struct mach_timebase_info timebase;
|
||||
|
||||
mach_timebase_info(&timebase);
|
||||
timebase_ratio = (double)timebase.numer / (double)timebase.denom
|
||||
* (double)1e-9;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
int i,j, r, c = 200;
|
||||
long long t = 0;
|
||||
|
||||
InitTimer();
|
||||
|
||||
for (i = 0; i < c; i++) {
|
||||
const int delay = rand() / (RAND_MAX / 1e5);
|
||||
j = GetTimer();
|
||||
#if 1
|
||||
r = usec_sleep(delay);
|
||||
#else
|
||||
r = sleep_accurate(delay / 1e6) * 1e6;
|
||||
#endif
|
||||
j = (GetTimer() - j) - delay;
|
||||
printf("sleep time:%8i %5i (%i)\n", delay, j, j - r);
|
||||
t += j - r;
|
||||
}
|
||||
fprintf(stderr, "average error:\t%lli\n", t / c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -26,35 +26,27 @@
|
||||
#include "config.h"
|
||||
#include "timer.h"
|
||||
|
||||
int usec_sleep(int usec_delay)
|
||||
void mp_sleep_us(int64_t us)
|
||||
{
|
||||
if (us < 0)
|
||||
return;
|
||||
#ifdef HAVE_NANOSLEEP
|
||||
struct timespec ts;
|
||||
ts.tv_sec = usec_delay / 1000000;
|
||||
ts.tv_nsec = (usec_delay % 1000000) * 1000;
|
||||
return nanosleep(&ts, NULL);
|
||||
ts.tv_sec = us / 1000000;
|
||||
ts.tv_nsec = (us % 1000000) * 1000;
|
||||
nanosleep(&ts, NULL);
|
||||
#else
|
||||
return usleep(usec_delay);
|
||||
usleep(us);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns current time in microseconds
|
||||
unsigned int GetTimer(void)
|
||||
uint64_t mp_raw_time_us(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return tv.tv_sec * 1000000 + tv.tv_usec;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||
}
|
||||
|
||||
// Returns current time in milliseconds
|
||||
unsigned int GetTimerMS(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv,NULL);
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
// Initialize timer, must be called at least once at start
|
||||
void InitTimer(void)
|
||||
void mp_raw_time_init(void)
|
||||
{
|
||||
}
|
||||
|
@ -22,27 +22,25 @@
|
||||
#include <mmsystem.h>
|
||||
#include "timer.h"
|
||||
|
||||
// Returns current time in microseconds
|
||||
unsigned int GetTimer(void)
|
||||
void mp_sleep_us(int64_t us)
|
||||
{
|
||||
return timeGetTime() * 1000;
|
||||
if (us < 0)
|
||||
return;
|
||||
// Sleep(0) won't sleep for one clocktick as the unix usleep
|
||||
// instead it will only make the thread ready
|
||||
// it may take some time until it actually starts to run again
|
||||
if (us < 1000)
|
||||
us = 1000;
|
||||
Sleep(us / 1000);
|
||||
}
|
||||
|
||||
// Returns current time in milliseconds
|
||||
unsigned int GetTimerMS(void)
|
||||
uint64_t mp_raw_time_us(void)
|
||||
{
|
||||
return timeGetTime() ;
|
||||
return timeGetTime() * 1000;
|
||||
}
|
||||
|
||||
int usec_sleep(int usec_delay){
|
||||
// Sleep(0) won't sleep for one clocktick as the unix usleep
|
||||
// instead it will only make the thread ready
|
||||
// it may take some time until it actually starts to run again
|
||||
if(usec_delay<1000)usec_delay=1000;
|
||||
Sleep( usec_delay/1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InitTimer(void)
|
||||
void mp_raw_time_init(void)
|
||||
{
|
||||
// request 1ms timer resolution
|
||||
timeBeginPeriod(1);
|
||||
}
|
||||
|
82
osdep/timer.c
Normal file
82
osdep/timer.c
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* 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.
|
||||
*
|
||||
* mpv 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
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
static uint64_t raw_time_offset;
|
||||
|
||||
void mp_time_init(void)
|
||||
{
|
||||
mp_raw_time_init();
|
||||
srand(mp_raw_time_us());
|
||||
raw_time_offset = mp_raw_time_us();
|
||||
// Arbitrary additional offset to avoid confusing relative/absolute times.
|
||||
// Also,we rule that the timer never returns 0 (so default-initialized
|
||||
// time values will be always in the past).
|
||||
raw_time_offset -= 10000000;
|
||||
}
|
||||
|
||||
int64_t mp_time_us(void)
|
||||
{
|
||||
return mp_raw_time_us() - raw_time_offset;
|
||||
}
|
||||
|
||||
double mp_time_sec(void)
|
||||
{
|
||||
return mp_time_us() / (double)(1000 * 1000);
|
||||
}
|
||||
|
||||
unsigned int GetTimer(void)
|
||||
{
|
||||
return mp_time_us();
|
||||
}
|
||||
|
||||
unsigned int GetTimerMS(void)
|
||||
{
|
||||
return (mp_time_us() + 500) / 1000;
|
||||
}
|
||||
|
||||
int usec_sleep(int usec_delay)
|
||||
{
|
||||
mp_sleep_us(usec_delay);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
int c = 200;
|
||||
int64_t j, r, t = 0;
|
||||
|
||||
mp_time_init();
|
||||
|
||||
for (int i = 0; i < c; i++) {
|
||||
const int delay = rand() / (RAND_MAX / 1e5);
|
||||
r = mp_time_us();
|
||||
mp_sleep_us(delay);
|
||||
j = (mp_time_us() - r) - delay;
|
||||
printf("sleep time: sleep=%8i err=%5i\n", delay, (int)j);
|
||||
t += j;
|
||||
}
|
||||
fprintf(stderr, "average error:\t%i\n", (int)(t / c));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -19,10 +19,28 @@
|
||||
#ifndef MPLAYER_TIMER_H
|
||||
#define MPLAYER_TIMER_H
|
||||
|
||||
void InitTimer(void);
|
||||
unsigned int GetTimer(void);
|
||||
unsigned int GetTimerMS(void);
|
||||
#include <inttypes.h>
|
||||
|
||||
// Initialize timer, must be called at least once at start.
|
||||
void mp_time_init(void);
|
||||
|
||||
// Return time in microseconds. Never wraps. Never returns 0 or negative values.
|
||||
int64_t mp_time_us(void);
|
||||
|
||||
// Return time in seconds. Can have down to 1 microsecond resolution, but will
|
||||
// be much worse when casted to float.
|
||||
double mp_time_sec(void);
|
||||
|
||||
// Provided by OS specific functions (timer-linux.c)
|
||||
void mp_raw_time_init(void);
|
||||
uint64_t mp_raw_time_us(void);
|
||||
|
||||
// Sleep in microseconds.
|
||||
void mp_sleep_us(int64_t us);
|
||||
|
||||
// Legacy timer functions. These can wrap.
|
||||
unsigned int GetTimer(void); // in us
|
||||
unsigned int GetTimerMS(void); // in ms
|
||||
int usec_sleep(int usec_delay);
|
||||
|
||||
#endif /* MPLAYER_TIMER_H */
|
||||
|
Loading…
Reference in New Issue
Block a user