[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