| Index: src/ply-image.c
|
| diff --git a/src/ply-image.c b/src/ply-image.c
|
| index 58e1daea3d5050723e5024557fb555cbb1f46d1f..3395c9200b6d3697678562d79b786d510cf27e8f 100644
|
| --- a/src/ply-image.c
|
| +++ b/src/ply-image.c
|
| @@ -489,33 +489,27 @@ ply_frame_buffer_show_file_at_xy(ply_frame_buffer_t *buffer, const char *path,
|
| ply_image_free (image);
|
| }
|
|
|
| -/*
|
| - * Compute the difference in nanoseconds between two timevals. Return 0 if the
|
| - * clock is not reliable.
|
| - */
|
| -int64_t difference_nsec(struct timespec x, struct timespec y)
|
| -{
|
| - int64_t z;
|
|
|
| - if (bad_clock)
|
| - {
|
| - return 0;
|
| - }
|
| -
|
| - z = x.tv_sec - y.tv_sec;
|
| - z *= BILLION;
|
| - z += x.tv_nsec - y.tv_nsec;
|
| - return z;
|
| +int64_t timespec_to_nsec(struct timespec ts)
|
| +{
|
| + int64_t nsec;
|
| + nsec = ts.tv_sec;
|
| + nsec *= BILLION;
|
| + nsec += ts.tv_nsec;
|
| + return nsec;
|
| }
|
|
|
|
|
| -void gettime_check(struct timespec *ts)
|
| +int64_t gettime_check(void)
|
| {
|
| - int r = clock_gettime(CLOCK_MONOTONIC, ts);
|
| + struct timespec ts;
|
| + int r = clock_gettime(CLOCK_MONOTONIC, &ts);
|
| if (r)
|
| {
|
| bad_clock = 1;
|
| + return 0;
|
| }
|
| + return timespec_to_nsec(ts);
|
| }
|
|
|
|
|
| @@ -584,9 +578,8 @@ main (int argc,
|
| /*
|
| * Animate frames.
|
| */
|
| - struct timespec then, now;
|
| - int64_t error_nsec;
|
| - int64_t interval_nsec;
|
| + int64_t draw_time_nsec, frame_period_nsec;
|
| + int64_t sleep_time_nsec, now_nsec, then_nsec;
|
|
|
| xoff = strtol (argv[2], &endptr, 10);
|
| if (endptr == argv[2] || *endptr != '\0')
|
| @@ -603,33 +596,39 @@ main (int argc,
|
| * Begin animation.
|
| *
|
| * The first time around, we don't know how long it takes to draw a
|
| - * frame, so we assume it's instantaneous. After that, we assume
|
| - * that the drawing time for the previous cycle is a good estimate
|
| - * for the next cycle. Errors may be introduced by different frame
|
| - * size and complexity (PNG decoding).
|
| + * frame, so we approximate it as 0. After that, we assume that the
|
| + * drawing time for the previous cycle is a good estimate for the
|
| + * next cycle. Errors may be introduced by different frame size and
|
| + * complexity (PNG decoding) and by the CPU load.
|
| */
|
| - error_nsec = 0;
|
| - interval_nsec = BILLION / frame_rate;
|
| - gettime_check (&now);
|
| + draw_time_nsec = 0;
|
| + frame_period_nsec = BILLION / frame_rate;
|
| + now_nsec = gettime_check ();
|
|
|
| for (i = 4; i < argc; i++)
|
| {
|
| /*
|
| - * Before displaying the next frame, sleep for the inter-frame
|
| - * interval, adjusted by the error in the previous cycle.
|
| - * Positive error means the last cycle took longer than desired.
|
| + * Before displaying the next frame, sleep for the right amount
|
| + * of time so that the achieved period approximates the desired
|
| + * period.
|
| */
|
| - if (interval_nsec - error_nsec > 0)
|
| + sleep_time_nsec = frame_period_nsec - draw_time_nsec;
|
| + if (sleep_time_nsec > 0)
|
| {
|
| struct timespec req;
|
| - req.tv_sec = (interval_nsec - error_nsec) / BILLION;
|
| - req.tv_nsec = (interval_nsec - error_nsec) % BILLION;
|
| + req.tv_sec = sleep_time_nsec / BILLION;
|
| + req.tv_nsec = sleep_time_nsec % BILLION;
|
| nanosleep (&req, NULL);
|
| }
|
| ply_frame_buffer_show_file_at_xy (buffer, argv[i], xoff, yoff);
|
| - then = now;
|
| - gettime_check (&now);
|
| - error_nsec = difference_nsec (now, then) - interval_nsec;
|
| + then_nsec = now_nsec;
|
| + now_nsec = gettime_check ();
|
| + /*
|
| + * If the clock is bad (unlikely), assume draw time is
|
| + * instantaneous as a rough guess.
|
| + */
|
| + draw_time_nsec = bad_clock ? 0 :
|
| + now_nsec - then_nsec - sleep_time_nsec;
|
| }
|
| }
|
| }
|
|
|