From: Vincent Stehlé Date: Fri, 10 Aug 2012 14:45:50 +0000 (+0200) Subject: disp: new option --fps to maintain playback rate X-Git-Tag: glsdk-6_00_00_07~18 X-Git-Url: https://git.ti.com/gitweb?p=glsdk%2Fomapdrmtest.git;a=commitdiff_plain;h=deb56e3c92034d4d0ea8b1001da0f90b988d60da disp: new option --fps to maintain playback rate Add a new rate control mechanism to the generic display, to allow forcing the playback rate from command line. We add rate control calls in the generic display functions disp_post_buffer() and disp_post_vid_buffer(). As this is in the generic display part, x11 and kms (and future) displays benefit from that mechanism. We use the mark() and usleep() functions for the rate control implementation, and we do also filter a bit the sleep duration, to avoid being too "choppy". Signed-off-by: Vincent Stehlé --- diff --git a/util/util.c b/util/util.c index 36c4ad9..3b3ca86 100644 --- a/util/util.c +++ b/util/util.c @@ -35,6 +35,9 @@ void disp_x11_close(struct display *disp); void disp_usage(void) { + MSG("Generic Display options:"); + MSG("\t--fps \tforce playback rate (0 means \"do not force\")"); + #ifdef HAVE_X11 disp_x11_usage(); #endif @@ -45,11 +48,29 @@ struct display * disp_open(int argc, char **argv) { struct display *disp; + int i, fps = 0; + + for (i = 1; i < argc; i++) { + if (!argv[i]) { + continue; + } + if (!strcmp("--fps", argv[i])) { + argv[i++] = NULL; + + if (sscanf(argv[i], "%d", &fps) != 1) { + ERROR("invalid arg: %s", argv[i]); + return NULL; + } + + MSG("Forcing playback rate at %d fps.", fps); + argv[i] = NULL; + } + } #ifdef HAVE_X11 disp = disp_x11_open(argc, argv); if (disp) - return disp; + goto out; #endif disp = disp_kms_open(argc, argv); @@ -58,6 +79,8 @@ disp_open(int argc, char **argv) ERROR("unable to create display"); } +out: + disp->rtctl.fps = fps; return disp; } @@ -111,6 +134,56 @@ disp_put_vid_buffer(struct display *disp, struct buffer *buf) list_add(&buf->unlocked, &disp->unlocked); } +/* Maintain playback rate if fps > 0. */ +static void maintain_playback_rate(struct rate_control *p) +{ + long usecs_since_last_frame; + int usecs_between_frames, usecs_to_sleep; + + if (p->fps <= 0) + return; + + usecs_between_frames = 1000000 / p->fps; + usecs_since_last_frame = mark(&p->last_frame_mark); + MSG("fps: %.02f", 1000000.0 / usecs_since_last_frame); + usecs_to_sleep = usecs_between_frames - usecs_since_last_frame + p->usecs_to_sleep; + + if (usecs_to_sleep < 0) + usecs_to_sleep = 0; + + /* mark() has a limitation that >1s time deltas will make the whole + * loop diverge. Workaround that limitation by clamping our desired sleep time + * to a maximum. TODO: Remove when mark() is in better shape. */ + if (usecs_to_sleep >= 1000000) + usecs_to_sleep = 999999; + + /* We filter a bit our rate adaptation, to avoid being too "choppy". + * Adjust the "alpha" value as needed. */ + p->usecs_to_sleep = ((67 * p->usecs_to_sleep) + (33 * usecs_to_sleep)) / 100; + + if (p->usecs_to_sleep >= 1) { + MSG("sleeping %dus", p->usecs_to_sleep); + usleep(p->usecs_to_sleep); + } +} + +/* flip to / post the specified buffer */ +int +disp_post_buffer(struct display *disp, struct buffer *buf) +{ + maintain_playback_rate(&disp->rtctl); + return disp->post_buffer(disp, buf); +} + +/* flip to / post the specified video buffer */ +int +disp_post_vid_buffer(struct display *disp, struct buffer *buf, + uint32_t x, uint32_t y, uint32_t w, uint32_t h) +{ + maintain_playback_rate(&disp->rtctl); + return disp->post_vid_buffer(disp, buf, x, y, w, h); +} + struct buffer * disp_get_fb(struct display *disp) { diff --git a/util/util.h b/util/util.h index 53b6e1c..505bdcb 100644 --- a/util/util.h +++ b/util/util.h @@ -56,11 +56,20 @@ struct buffer { struct list unlocked; }; +/* State variables, used to maintain the playback rate. */ +struct rate_control { + int fps; /* When > zero, we maintain playback rate. */ + long last_frame_mark; /* The time when the last frame was displayed, + * as returned by the mark() function. */ + int usecs_to_sleep; /* Number of useconds we have slep last frame. */ +}; + struct display { int fd; uint32_t width, height; struct omap_device *dev; struct list unlocked; + struct rate_control rtctl; struct buffer ** (*get_buffers)(struct display *disp, uint32_t n); struct buffer ** (*get_vid_buffers)(struct display *disp, @@ -93,19 +102,13 @@ struct buffer ** disp_get_vid_buffers(struct display *disp, uint32_t n, uint32_t fourcc, uint32_t w, uint32_t h); /* flip to / post the specified buffer */ -static inline int -disp_post_buffer(struct display *disp, struct buffer *buf) -{ - return disp->post_buffer(disp, buf); -} +int +disp_post_buffer(struct display *disp, struct buffer *buf); /* flip to / post the specified video buffer */ -static inline int +int disp_post_vid_buffer(struct display *disp, struct buffer *buf, - uint32_t x, uint32_t y, uint32_t w, uint32_t h) -{ - return disp->post_vid_buffer(disp, buf, x, y, w, h); -} + uint32_t x, uint32_t y, uint32_t w, uint32_t h); /* allocate a buffer from pool created by disp_get_vid_buffers() */ struct buffer * disp_get_vid_buffer(struct display *disp);