[FFmpeg-devel] [PATCH] Use monotonic clock for measuring rel time.
Olivier Langlois
olivier at trillion01.com
Mon Mar 31 08:25:17 CEST 2014
Whenever time is requested to measure relative time, the monotonic clock,
when available, is superior to the system realtime clock because:
It is not affected by discontinuous jumps in the system time
Concretely that means that successive timestamps will never go backward and
time difference between 2 events will never be negative because of clock
setting between the 2 events.
Hence, this is an improvement to ffmpeg by using a more stable time source.
Signed-off-by: Olivier Langlois <olivier at trillion01.com>
---
cmdutils_opencl.c | 4 ++--
configure | 2 ++
ffmpeg.c | 10 +++++-----
ffplay.c | 26 +++++++++++++-------------
libavcodec/dct-test.c | 8 ++++----
libavcodec/fft-test.c | 4 ++--
libavcodec/motion-test.c | 4 ++--
libavdevice/alsa-audio-dec.c | 2 +-
libavdevice/bktr.c | 6 +++---
libavdevice/fbdev_dec.c | 9 +++------
libavdevice/openal-dec.c | 2 +-
libavdevice/oss_audio.c | 2 +-
libavdevice/sndio_dec.c | 2 +-
libavdevice/v4l.c | 11 ++++-------
libavdevice/v4l2.c | 10 ----------
libavdevice/x11grab.c | 9 +++------
libavformat/avio.c | 4 ++--
libavformat/network.c | 4 ++--
libavformat/sapenc.c | 2 +-
libavformat/utils.c | 2 +-
libavutil/time.c | 32 +++++++++++++++++++++++++++++++-
libavutil/time.h | 20 ++++++++++++++++++++
tools/aviocat.c | 6 +++---
23 files changed, 107 insertions(+), 74 deletions(-)
diff --git a/cmdutils_opencl.c b/cmdutils_opencl.c
index 2a04db9..d0ced05 100644
--- a/cmdutils_opencl.c
+++ b/cmdutils_opencl.c
@@ -181,12 +181,12 @@ static int64_t run_opencl_bench(AVOpenCLExternalEnv *ext_opencl_env)
OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &width);
OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &height);
- start = av_gettime();
+ start = av_gettime_monotonic();
for (i = 0; i < OPENCL_NB_ITER; i++)
OCLCHECK(clEnqueueNDRangeKernel, ext_opencl_env->command_queue, kernel, 2, NULL,
global_work_size_2d, local_work_size_2d, 0, NULL, NULL);
clFinish(ext_opencl_env->command_queue);
- ret = (av_gettime() - start)/OPENCL_NB_ITER;
+ ret = (av_gettime_monotonic() - start)/OPENCL_NB_ITER;
end:
if (kernel)
clReleaseKernel(kernel);
diff --git a/configure b/configure
index face2d2..f1e4071 100755
--- a/configure
+++ b/configure
@@ -1633,6 +1633,7 @@ SYSTEM_FUNCS="
access
aligned_malloc
clock_gettime
+ clock_nanosleep
closesocket
CommandLineToArgvW
CryptGenRandom
@@ -4432,6 +4433,7 @@ check_func ${malloc_prefix}posix_memalign && enable posix_memalign
check_func access
check_func clock_gettime || { check_func clock_gettime -lrt && add_extralibs -lrt; }
+check_func clock_nanosleep || { check_func clock_nanosleep && add_extralibs -lrt; }
check_func fcntl
check_func fork
check_func gethrtime
diff --git a/ffmpeg.c b/ffmpeg.c
index 25001f5..d0d86c0 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -2380,7 +2380,7 @@ static int transcode_init(void)
InputFile *ifile = input_files[i];
if (ifile->rate_emu)
for (j = 0; j < ifile->nb_streams; j++)
- input_streams[j + ifile->ist_index]->start = av_gettime();
+ input_streams[j + ifile->ist_index]->start = av_gettime_monotonic();
}
/* output stream init */
@@ -3171,7 +3171,7 @@ static int get_input_packet(InputFile *f, AVPacket *pkt)
for (i = 0; i < f->nb_streams; i++) {
InputStream *ist = input_streams[f->ist_index + i];
int64_t pts = av_rescale(ist->dts, 1000000, AV_TIME_BASE);
- int64_t now = av_gettime() - ist->start;
+ int64_t now = av_gettime_monotonic() - ist->start;
if (pts > now)
return AVERROR(EAGAIN);
}
@@ -3535,7 +3535,7 @@ static int transcode(void)
av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
}
- timer_start = av_gettime();
+ timer_start = av_gettime_monotonic();
#if HAVE_PTHREADS
if ((ret = init_input_threads()) < 0)
@@ -3543,7 +3543,7 @@ static int transcode(void)
#endif
while (!received_sigterm) {
- int64_t cur_time= av_gettime();
+ int64_t cur_time= av_gettime_monotonic();
/* if 'q' pressed, exits */
if (stdin_interaction)
@@ -3590,7 +3590,7 @@ static int transcode(void)
}
/* dump report by using the first video and audio streams */
- print_report(1, timer_start, av_gettime());
+ print_report(1, timer_start, av_gettime_monotonic());
/* close each encoder */
for (i = 0; i < nb_output_streams; i++) {
diff --git a/ffplay.c b/ffplay.c
index c86f94f..9d8bf65 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -899,7 +899,7 @@ static void video_audio_display(VideoState *s)
/* to be more precise, we take into account the time spent since
the last buffer computation */
if (audio_callback_time) {
- time_diff = av_gettime() - audio_callback_time;
+ time_diff = av_gettime_monotonic() - audio_callback_time;
delay -= (time_diff * s->audio_tgt.freq) / 1000000;
}
@@ -1132,7 +1132,7 @@ static double get_clock(Clock *c)
if (c->paused) {
return c->pts;
} else {
- double time = av_gettime() / 1000000.0;
+ double time = av_gettime_monotonic() / 1000000.0;
return c->pts_drift + time - (time - c->last_updated) * (1.0 - c->speed);
}
}
@@ -1147,7 +1147,7 @@ static void set_clock_at(Clock *c, double pts, int serial, double time)
static void set_clock(Clock *c, double pts, int serial)
{
- double time = av_gettime() / 1000000.0;
+ double time = av_gettime_monotonic() / 1000000.0;
set_clock_at(c, pts, serial, time);
}
@@ -1240,7 +1240,7 @@ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_by
static void stream_toggle_pause(VideoState *is)
{
if (is->paused) {
- is->frame_timer += av_gettime() / 1000000.0 + is->vidclk.pts_drift - is->vidclk.pts;
+ is->frame_timer += av_gettime_monotonic() / 1000000.0 + is->vidclk.pts_drift - is->vidclk.pts;
if (is->read_pause_return != AVERROR(ENOSYS)) {
is->vidclk.paused = 0;
}
@@ -1355,7 +1355,7 @@ static void video_refresh(void *opaque, double *remaining_time)
check_external_clock_speed(is);
if (!display_disable && is->show_mode != SHOW_MODE_VIDEO && is->audio_st) {
- time = av_gettime() / 1000000.0;
+ time = av_gettime_monotonic() / 1000000.0;
if (is->force_refresh || is->last_vis_time + rdftspeed < time) {
video_display(is);
is->last_vis_time = time;
@@ -1386,7 +1386,7 @@ retry:
}
if (lastvp->serial != vp->serial && !redisplay)
- is->frame_timer = av_gettime() / 1000000.0;
+ is->frame_timer = av_gettime_monotonic() / 1000000.0;
if (is->paused)
goto display;
@@ -1398,7 +1398,7 @@ retry:
else
delay = compute_target_delay(last_duration, is);
- time= av_gettime()/1000000.0;
+ time= av_gettime_monotonic()/1000000.0;
if (time < is->frame_timer + delay && !redisplay) {
*remaining_time = FFMIN(is->frame_timer + delay - time, *remaining_time);
return;
@@ -1472,7 +1472,7 @@ display:
int aqsize, vqsize, sqsize;
double av_diff;
- cur_time = av_gettime();
+ cur_time = av_gettime_monotonic();
if (!last_time || (cur_time - last_time) >= 30000) {
aqsize = 0;
vqsize = 0;
@@ -1967,7 +1967,7 @@ static int video_thread(void *arg)
goto the_end;
while (ret >= 0) {
- is->frame_last_returned_time = av_gettime() / 1000000.0;
+ is->frame_last_returned_time = av_gettime_monotonic() / 1000000.0;
ret = av_buffersink_get_frame_flags(filt_out, frame, 0);
if (ret < 0) {
@@ -1977,7 +1977,7 @@ static int video_thread(void *arg)
break;
}
- is->frame_last_filter_delay = av_gettime() / 1000000.0 - is->frame_last_returned_time;
+ is->frame_last_filter_delay = av_gettime_monotonic() / 1000000.0 - is->frame_last_returned_time;
if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0)
is->frame_last_filter_delay = 0;
tb = filt_out->inputs[0]->time_base;
@@ -2378,7 +2378,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
VideoState *is = opaque;
int audio_size, len1;
- audio_callback_time = av_gettime();
+ audio_callback_time = av_gettime_monotonic();
while (len > 0) {
if (is->audio_buf_index >= is->audio_buf_size) {
@@ -3162,7 +3162,7 @@ static void refresh_loop_wait_event(VideoState *is, SDL_Event *event) {
double remaining_time = 0.0;
SDL_PumpEvents();
while (!SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
- if (!cursor_hidden && av_gettime() - cursor_last_shown > CURSOR_HIDE_DELAY) {
+ if (!cursor_hidden && av_gettime_monotonic() - cursor_last_shown > CURSOR_HIDE_DELAY) {
SDL_ShowCursor(0);
cursor_hidden = 1;
}
@@ -3316,7 +3316,7 @@ static void event_loop(VideoState *cur_stream)
SDL_ShowCursor(1);
cursor_hidden = 0;
}
- cursor_last_shown = av_gettime();
+ cursor_last_shown = av_gettime_monotonic();
if (event.type == SDL_MOUSEBUTTONDOWN) {
x = event.button.x;
} else {
diff --git a/libavcodec/dct-test.c b/libavcodec/dct-test.c
index 6308348..6b331f5 100644
--- a/libavcodec/dct-test.c
+++ b/libavcodec/dct-test.c
@@ -348,7 +348,7 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed, c
init_block(block, test, is_idct, &prng, vals);
permute(block1, block, dct->format);
- ti = av_gettime();
+ ti = av_gettime_monotonic();
it1 = 0;
do {
for (it = 0; it < NB_ITS_SPEED; it++) {
@@ -357,7 +357,7 @@ static int dct_error(const struct algo *dct, int test, int is_idct, int speed, c
}
emms_c();
it1 += NB_ITS_SPEED;
- ti1 = av_gettime() - ti;
+ ti1 = av_gettime_monotonic() - ti;
} while (ti1 < 1000000);
printf("%s %s: %0.1f kdct/s\n", is_idct ? "IDCT" : "DCT", dct->name,
@@ -508,7 +508,7 @@ static void idct248_error(const char *name,
if (!speed)
return;
- ti = av_gettime();
+ ti = av_gettime_monotonic();
it1 = 0;
do {
for (it = 0; it < NB_ITS_SPEED; it++) {
@@ -518,7 +518,7 @@ static void idct248_error(const char *name,
}
emms_c();
it1 += NB_ITS_SPEED;
- ti1 = av_gettime() - ti;
+ ti1 = av_gettime_monotonic() - ti;
} while (ti1 < 1000000);
printf("%s %s: %0.1f kdct/s\n", 1 ? "IDCT248" : "DCT248", name,
diff --git a/libavcodec/fft-test.c b/libavcodec/fft-test.c
index ef1d622..e298c12 100644
--- a/libavcodec/fft-test.c
+++ b/libavcodec/fft-test.c
@@ -438,7 +438,7 @@ int main(int argc, char **argv)
/* we measure during about 1 seconds */
nb_its = 1;
for(;;) {
- time_start = av_gettime();
+ time_start = av_gettime_monotonic();
for (it = 0; it < nb_its; it++) {
switch (transform) {
case TRANSFORM_MDCT:
@@ -464,7 +464,7 @@ int main(int argc, char **argv)
#endif
}
}
- duration = av_gettime() - time_start;
+ duration = av_gettime_monotonic() - time_start;
if (duration >= 1000000)
break;
nb_its *= 2;
diff --git a/libavcodec/motion-test.c b/libavcodec/motion-test.c
index 53cfedb..fca7260 100644
--- a/libavcodec/motion-test.c
+++ b/libavcodec/motion-test.c
@@ -91,7 +91,7 @@ static void test_motion(const char *name,
emms_c();
/* speed test */
- ti = av_gettime();
+ ti = av_gettime_monotonic();
d1 = 0;
for(it=0;it<NB_ITS;it++) {
for(y=0;y<HEIGHT-17;y++) {
@@ -103,7 +103,7 @@ static void test_motion(const char *name,
}
emms_c();
dummy = d1; /* avoid optimization */
- ti = av_gettime() - ti;
+ ti = av_gettime_monotonic() - ti;
printf(" %0.0f kop/s\n",
(double)NB_ITS * (WIDTH - 16) * (HEIGHT - 16) /
diff --git a/libavdevice/alsa-audio-dec.c b/libavdevice/alsa-audio-dec.c
index 2cdf356..77b36e3 100644
--- a/libavdevice/alsa-audio-dec.c
+++ b/libavdevice/alsa-audio-dec.c
@@ -121,7 +121,7 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
ff_timefilter_reset(s->timefilter);
}
- dts = av_gettime();
+ dts = av_gettime_monotonic();
snd_pcm_delay(s->h, &delay);
dts -= av_rescale(delay + res, 1000000, s->sample_rate);
pkt->pts = ff_timefilter_update(s->timefilter, dts, s->last_period);
diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c
index 50dcc7d..93bfdbf 100644
--- a/libavdevice/bktr.c
+++ b/libavdevice/bktr.c
@@ -212,14 +212,14 @@ static void bktr_getframe(uint64_t per_frame)
{
uint64_t curtime;
- curtime = av_gettime();
+ curtime = av_gettime_monotonic();
if (!last_frame_time
|| ((last_frame_time + per_frame) > curtime)) {
if (!usleep(last_frame_time + per_frame + per_frame / 8 - curtime)) {
if (!nsignals)
av_log(NULL, AV_LOG_INFO,
"SLEPT NO signals - %d microseconds late\n",
- (int)(av_gettime() - last_frame_time - per_frame));
+ (int)(av_gettime_monotonic() - last_frame_time - per_frame));
}
}
nsignals = 0;
@@ -237,7 +237,7 @@ static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
bktr_getframe(s->per_frame);
- pkt->pts = av_gettime();
+ pkt->pts = av_gettime_monotonic();
memcpy(pkt->data, video_buf, video_buf_size);
return video_buf_size;
diff --git a/libavdevice/fbdev_dec.c b/libavdevice/fbdev_dec.c
index 01bc7c6..e1a2667 100644
--- a/libavdevice/fbdev_dec.c
+++ b/libavdevice/fbdev_dec.c
@@ -146,16 +146,15 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
{
FBDevContext *fbdev = avctx->priv_data;
int64_t curtime, delay;
- struct timespec ts;
int i, ret;
uint8_t *pin, *pout;
if (fbdev->time_frame == AV_NOPTS_VALUE)
- fbdev->time_frame = av_gettime();
+ fbdev->time_frame = av_gettime_monotonic();
/* wait based on the frame rate */
while (1) {
- curtime = av_gettime();
+ curtime = av_gettime_monotonic();
delay = fbdev->time_frame - curtime;
av_dlog(avctx,
"time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
@@ -166,9 +165,7 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
}
if (avctx->flags & AVFMT_FLAG_NONBLOCK)
return AVERROR(EAGAIN);
- ts.tv_sec = delay / 1000000;
- ts.tv_nsec = (delay % 1000000) * 1000;
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
+ av_usleep_monotonic(delay);
}
if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
diff --git a/libavdevice/openal-dec.c b/libavdevice/openal-dec.c
index 4c4ba28..3211f9d 100644
--- a/libavdevice/openal-dec.c
+++ b/libavdevice/openal-dec.c
@@ -193,7 +193,7 @@ static int read_packet(AVFormatContext* ctx, AVPacket *pkt)
/* Create a packet of appropriate size */
av_new_packet(pkt, nb_samples*ad->sample_step);
- pkt->pts = av_gettime();
+ pkt->pts = av_gettime_monotonic();
/* Fill the packet with the available samples */
alcCaptureSamples(ad->device, pkt->data, nb_samples);
diff --git a/libavdevice/oss_audio.c b/libavdevice/oss_audio.c
index 71bf636..aa3fcf9 100644
--- a/libavdevice/oss_audio.c
+++ b/libavdevice/oss_audio.c
@@ -253,7 +253,7 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
pkt->size = ret;
/* compute pts of the start of the packet */
- cur_time = av_gettime();
+ cur_time = av_gettime_monotonic();
bdelay = ret;
if (ioctl(s->fd, SNDCTL_DSP_GETISPACE, &abufi) == 0) {
bdelay += abufi.bytes;
diff --git a/libavdevice/sndio_dec.c b/libavdevice/sndio_dec.c
index 37c6983..383c8c5 100644
--- a/libavdevice/sndio_dec.c
+++ b/libavdevice/sndio_dec.c
@@ -73,7 +73,7 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
s->softpos += ret;
/* compute pts of the start of the packet */
- cur_time = av_gettime();
+ cur_time = av_gettime_monotonic();
bdelay = ret + s->hwpos - s->softpos;
diff --git a/libavdevice/v4l.c b/libavdevice/v4l.c
index d33f714..22434d9 100644
--- a/libavdevice/v4l.c
+++ b/libavdevice/v4l.c
@@ -189,7 +189,7 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
goto fail;
}
- s->time_frame = av_gettime() * s->time_base.den / s->time_base.num;
+ s->time_frame = av_gettime_monotonic() * s->time_base.den / s->time_base.num;
s->use_mmap = 0;
} else {
s->video_buf = mmap(0, s->gb_buffers.size, PROT_READ|PROT_WRITE, MAP_SHARED, video_fd, 0);
@@ -201,7 +201,7 @@ static int grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
}
}
s->gb_frame = 0;
- s->time_frame = av_gettime() * s->time_base.den / s->time_base.num;
+ s->time_frame = av_gettime_monotonic() * s->time_base.den / s->time_base.num;
/* start to grab the first frame */
s->gb_buf.frame = s->gb_frame % s->gb_buffers.frames;
@@ -283,14 +283,13 @@ static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
{
VideoData *s = s1->priv_data;
int64_t curtime, delay;
- struct timespec ts;
/* Calculate the time of the next frame */
s->time_frame += INT64_C(1000000);
/* wait based on the frame rate */
for(;;) {
- curtime = av_gettime();
+ curtime = av_gettime_monotonic();
delay = s->time_frame * s->time_base.num / s->time_base.den - curtime;
if (delay <= 0) {
if (delay < INT64_C(-1000000) * s->time_base.num / s->time_base.den) {
@@ -299,9 +298,7 @@ static int grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
}
break;
}
- ts.tv_sec = delay / 1000000;
- ts.tv_nsec = (delay % 1000000) * 1000;
- nanosleep(&ts, NULL);
+ av_usleep_monotonic(delay);
}
if (av_new_packet(pkt, s->frame_size) < 0)
diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index c671e3a..331dc8f 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -424,16 +424,6 @@ static void mmap_release_buffer(void *opaque, uint8_t *data)
avpriv_atomic_int_add_and_fetch(&s->buffers_queued, 1);
}
-#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
-static int64_t av_gettime_monotonic(void)
-{
- struct timespec tv;
-
- clock_gettime(CLOCK_MONOTONIC, &tv);
- return (int64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
-}
-#endif
-
static int init_convert_timestamp(AVFormatContext *ctx, int64_t ts)
{
struct video_data *s = ctx->priv_data;
diff --git a/libavdevice/x11grab.c b/libavdevice/x11grab.c
index d38c55d..65a1831 100644
--- a/libavdevice/x11grab.c
+++ b/libavdevice/x11grab.c
@@ -319,7 +319,7 @@ x11grab_read_header(AVFormatContext *s1)
x11grab->frame_size = x11grab->width * x11grab->height * image->bits_per_pixel/8;
x11grab->dpy = dpy;
x11grab->time_base = av_inv_q(x11grab->framerate);
- x11grab->time_frame = av_gettime() / av_q2d(x11grab->time_base);
+ x11grab->time_frame = av_gettime_monotonic() / av_q2d(x11grab->time_base);
x11grab->x_off = x_off;
x11grab->y_off = y_off;
x11grab->image = image;
@@ -479,14 +479,13 @@ x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
int follow_mouse = s->follow_mouse;
int64_t curtime, delay;
- struct timespec ts;
/* Calculate the time of the next frame */
s->time_frame += INT64_C(1000000);
/* wait based on the frame rate */
for(;;) {
- curtime = av_gettime();
+ curtime = av_gettime_monotonic();
delay = s->time_frame * av_q2d(s->time_base) - curtime;
if (delay <= 0) {
if (delay < INT64_C(-1000000) * av_q2d(s->time_base)) {
@@ -494,9 +493,7 @@ x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
}
break;
}
- ts.tv_sec = delay / 1000000;
- ts.tv_nsec = (delay % 1000000) * 1000;
- nanosleep(&ts, NULL);
+ av_usleep_monotonic(delay);
}
av_init_packet(pkt);
diff --git a/libavformat/avio.c b/libavformat/avio.c
index 4edaaa6..4b70b7f 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -312,8 +312,8 @@ static inline int retry_transfer_wrapper(URLContext *h, uint8_t *buf,
} else {
if (h->rw_timeout) {
if (!wait_since)
- wait_since = av_gettime();
- else if (av_gettime() > wait_since + h->rw_timeout)
+ wait_since = av_gettime_monotonic();
+ else if (av_gettime_monotonic() > wait_since + h->rw_timeout)
return AVERROR(EIO);
}
av_usleep(1000);
diff --git a/libavformat/network.c b/libavformat/network.c
index 5e2bcf8..195b615 100644
--- a/libavformat/network.c
+++ b/libavformat/network.c
@@ -163,8 +163,8 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt
return ret;
if (timeout > 0) {
if (!wait_start)
- wait_start = av_gettime();
- else if (av_gettime() - wait_start > timeout)
+ wait_start = av_gettime_monotonic();
+ else if (av_gettime_monotonic() - wait_start > timeout)
return AVERROR(ETIMEDOUT);
}
}
diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c
index 738e8b8..d405ab3 100644
--- a/libavformat/sapenc.c
+++ b/libavformat/sapenc.c
@@ -245,7 +245,7 @@ static int sap_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVFormatContext *rtpctx;
struct SAPState *sap = s->priv_data;
- int64_t now = av_gettime();
+ int64_t now = av_gettime_monotonic();
if (!sap->last_time || now - sap->last_time > 5000000) {
int ret = ffurl_write(sap->ann_fd, sap->ann, sap->ann_size);
diff --git a/libavformat/utils.c b/libavformat/utils.c
index a10c397..37286f1 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -811,7 +811,7 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
/* TODO: audio: time filter; video: frame reordering (pts != dts) */
if (s->use_wallclock_as_timestamps)
- pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base);
+ pkt->dts = pkt->pts = av_rescale_q(av_gettime_monotonic(), AV_TIME_BASE_Q, st->time_base);
if (!pktl && st->request_probe <= 0)
return ret;
diff --git a/libavutil/time.c b/libavutil/time.c
index 5a00e70..82f0abc 100644
--- a/libavutil/time.c
+++ b/libavutil/time.c
@@ -38,7 +38,15 @@
int64_t av_gettime(void)
{
-#if HAVE_GETTIMEOFDAY
+#if HAVE_CLOCK_GETTIME
+ /*
+ * POSIX.1-2008 marks gettimeofday() as obsolete,
+ * recommending the use of clock_gettime(2) instead.
+ */
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+#elif HAVE_GETTIMEOFDAY
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
@@ -53,6 +61,17 @@ int64_t av_gettime(void)
#endif
}
+int64_t av_gettime_monotonic(void)
+{
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+#else
+ return av_gettime();
+#endif
+}
+
int av_usleep(unsigned usec)
{
#if HAVE_NANOSLEEP
@@ -68,3 +87,14 @@ int av_usleep(unsigned usec)
return AVERROR(ENOSYS);
#endif
}
+
+int av_usleep_monotonic(int64_t usec)
+{
+#if HAVE_CLOCK_NANOSLEEP && defined(CLOCK_MONOTONIC)
+ struct timespec ts = { usec / 1000000, usec % 1000000 * 1000 };
+ while (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts) < 0 && errno == EINTR);
+ return 0;
+#else
+ return av_usleep((unsigned)usec);
+#endif
+}
diff --git a/libavutil/time.h b/libavutil/time.h
index 90eb436..8e87717 100644
--- a/libavutil/time.h
+++ b/libavutil/time.h
@@ -29,6 +29,26 @@
int64_t av_gettime(void);
/**
+ * Get the current time in microseconds from the monotonic clock
+ * if available. If a monotonic clock is not available on the
+ * targeted platform, the implementation fallsback on using
+ * av_gettime().
+ */
+int64_t av_gettime_monotonic(void);
+
+/**
+ * Sleep for a period of time by using the monotic clock.
+ * If a monotonic clock is not available on the targeted platform,
+ * the implementation fallsback on using av_usleep. Although the duration
+ * is expressed in microseconds, the actual delay may be rounded to the
+ * precision of the system timer.
+ *
+ * @param usec Number of microseconds to sleep.
+ * @return zero on success or (negative) error code.
+ */
+int av_usleep_monotonic(int64_t usec);
+
+/**
* Sleep for a period of time. Although the duration is expressed in
* microseconds, the actual delay may be rounded to the precision of the
* system timer.
diff --git a/tools/aviocat.c b/tools/aviocat.c
index 56b918e..14619ab 100644
--- a/tools/aviocat.c
+++ b/tools/aviocat.c
@@ -82,7 +82,7 @@ int main(int argc, char **argv)
goto fail;
}
- start_time = av_gettime();
+ start_time = av_gettime_monotonic();
while (1) {
uint8_t buf[1024];
int n;
@@ -93,8 +93,8 @@ int main(int argc, char **argv)
stream_pos += n;
if (bps) {
avio_flush(output);
- while ((av_gettime() - start_time) * bps / AV_TIME_BASE < stream_pos)
- av_usleep(50 * 1000);
+ while ((av_gettime_monotonic() - start_time) * bps / AV_TIME_BASE < stream_pos)
+ av_usleep_monotonic(50 * 1000);
}
}
--
1.9.1
More information about the ffmpeg-devel
mailing list