[FFmpeg-devel] [PATCH 1/6] lavu: add av_gettime_relative()

Olivier Langlois olivier at trillion01.com
Tue May 6 23:16:46 CEST 2014


These functions are using the POSIX clock_gettime() function with the
CLOCK_MONOTONIC clock id. If these are not present on the targeted
platform, the new functions will fallback on using the original realtime functions
av_gettime() and av_usleep().

Monotonic support can be added on other platforms with their
equivalent native system API eventually if possible.

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

In a future step, offering the flexibility to let the user choose between
rt and monotonic clock for avdevices packets will be investigated.

It is very easy to experience the issues that this patch attempt to address
by rewinding back in the past the system time while ffmpeg is running.

this is breaking the ffmpeg report printing (ffmepg.c:print_report()) and
the the rate emulator functionality (-re) without the patch.

Signed-off-by: Olivier Langlois <olivier at trillion01.com>
---
 configure          |  2 ++
 libavdevice/v4l2.c | 14 ++------------
 libavutil/time.c   | 31 ++++++++++++++++++++++++++++++-
 libavutil/time.h   | 15 +++++++++++++++
 4 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/configure b/configure
index e5ff72b..656ae3d 100755
--- a/configure
+++ b/configure
@@ -1659,6 +1659,7 @@ SYSTEM_FUNCS="
     access
     aligned_malloc
     clock_gettime
+    clock_nanosleep
     closesocket
     CommandLineToArgvW
     CoTaskMemFree
@@ -4489,6 +4490,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/libavdevice/v4l2.c b/libavdevice/v4l2.c
index 4b3f6a8..cbc70e6 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;
@@ -448,7 +438,7 @@ static int init_convert_timestamp(AVFormatContext *ctx, int64_t ts)
     }
 #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
     if (ctx->streams[0]->avg_frame_rate.num) {
-        now = av_gettime_monotonic();
+        now = av_gettime_relative();
         if (s->ts_mode == V4L_TS_MONO2ABS ||
             (ts <= now + 1 * AV_TIME_BASE && ts >= now - 10 * AV_TIME_BASE)) {
             AVRational tb = {AV_TIME_BASE, 1};
@@ -479,7 +469,7 @@ static int convert_timestamp(AVFormatContext *ctx, int64_t *ts)
 #if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
     if (s->timefilter) {
         int64_t nowa = av_gettime();
-        int64_t nowm = av_gettime_monotonic();
+        int64_t nowm = av_gettime_relative();
         ff_timefilter_update(s->timefilter, nowa, nowm - s->last_time_m);
         s->last_time_m = nowm;
         *ts = ff_timefilter_eval(s->timefilter, *ts - nowm);
diff --git a/libavutil/time.c b/libavutil/time.c
index 5a00e70..0406ae8 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,26 @@ int64_t av_gettime(void)
 #endif
 }
 
+int64_t av_gettime_relative(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_gettime_relative_is_monotonic(void)
+{
+#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC)
+    return 1;
+#else
+    return 0;
+#endif
+}
+
 int av_usleep(unsigned usec)
 {
 #if HAVE_NANOSLEEP
@@ -68,3 +96,4 @@ int av_usleep(unsigned usec)
     return AVERROR(ENOSYS);
 #endif
 }
+
diff --git a/libavutil/time.h b/libavutil/time.h
index 90eb436..910d28e 100644
--- a/libavutil/time.h
+++ b/libavutil/time.h
@@ -29,6 +29,21 @@
 int64_t av_gettime(void);
 
 /**
+ * Get the current time in microseconds since some unspecified starting point.
+ * On platforms that support it, the time comes from a monotonic clock
+ * This property makes this time source ideal for measuring relative time.
+ * If a monotonic clock is not available on the targeted platform, the
+ * implementation fallsback on using av_gettime().
+ */
+int64_t av_gettime_relative(void);
+
+/**
+ * Indicates with a boolean result if the av_gettime_relative() time source
+ * is monotonic.
+ */
+int av_gettime_relative_is_monotonic(void);
+
+/**
  * 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.
-- 
1.9.2



More information about the ffmpeg-devel mailing list