diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2011-04-11 02:58:50 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2011-04-11 02:58:50 +0000 |
commit | 31e450e813cbb66e2f19360ada9b62b4b17b5255 (patch) | |
tree | fba2cc2115e69f06963ad9297d745b5582883e28 /app/video | |
parent | bf58a224b11bac70e337d6e51bc46a5272f6c1a9 (diff) |
* use VIDIOC_ENUM_FRAMEINTERVALS to get the supported frame intervals
and display the frame rates if at least on -v is used.
* set/get the video(4) device's frame rate using VIDIOC_{S,G}_PARM.
* add new option -R which dsables frame rate adjustment. only really
useful for video(4) devices, to see the difference between the frame
rate the device generates and what it says it's configured for ...
many devices don't generate the rate they are configured if they
aren't getting enough light ...
* poll(2) input with INFTIM instead of 0 timeout, and handle the poll(2)
call being interrupted by the frame timer.
* only use usleep(3) to wait for frames if the input is a file, and
in that case, sleep for a full frame interval or until interrupted
by the frame timer.
* update the manual to describe the new -R option, that -r now sets
video(4) frame rate, and that at least one -v will display supported
properties of the hardware.
Diffstat (limited to 'app/video')
-rw-r--r-- | app/video/video.1 | 22 | ||||
-rw-r--r-- | app/video/video.c | 171 |
2 files changed, 157 insertions, 36 deletions
diff --git a/app/video/video.1 b/app/video/video.1 index a6318952d..467690801 100644 --- a/app/video/video.1 +++ b/app/video/video.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: video.1,v 1.8 2011/03/18 20:08:58 sobrado Exp $ +.\" $OpenBSD: video.1,v 1.9 2011/04/11 02:58:49 jakemsr Exp $ .\" .\" Copyright (c) 2010 Jacob Meuser <jakemsr@openbsd.org> .\" @@ -15,7 +15,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" -.Dd $Mdocdate: March 18 2011 $ +.Dd $Mdocdate: April 11 2011 $ .Dt VIDEO 1 .Os .Sh NAME @@ -25,7 +25,7 @@ .Sh SYNOPSIS .Nm .Bk -words -.Op Fl v +.Op Fl Rv .Op Fl a Ar adaptor .Op Fl e Ar encoding .Op Fl f Ar file @@ -128,6 +128,8 @@ If is .Ql - , frames will be written to standard output. +.It Fl R +Disable frame rate adjustment. .It Fl r Ar rate Rate in frames per second at which to read. Must be an integer greater than 0. @@ -136,13 +138,15 @@ If the option is not specified, frames will be read as quickly as possible. If reading from a .Xr video 4 -device, frames will be read as quickly as they are available from -the device, but will be displayed and/or written to +device, the device's frame rate will be set to the frame rate the device +supports that is closest to +.Ar rate . +Frames will be read as quickly as they are available from the device, but +will be displayed and/or written to .Ar output -at the rate specified. -This is done because -.Xr video 4 -does not yet support setting the device frame rate. +at the rate specified, unless the +.Fl R +option is used. .It Fl s Ar size Size of frames to read. The format of diff --git a/app/video/video.c b/app/video/video.c index ce03b7ac4..5abea90ab 100644 --- a/app/video/video.c +++ b/app/video/video.c @@ -1,4 +1,4 @@ -/* $OpenBSD: video.c,v 1.8 2010/10/15 14:21:20 jakemsr Exp $ */ +/* $OpenBSD: video.c,v 1.9 2011/04/11 02:58:49 jakemsr Exp $ */ /* * Copyright (c) 2010 Jacob Meuser <jakemsr@openbsd.org> * @@ -19,6 +19,7 @@ #include <sys/types.h> #include <sys/videoio.h> #include <sys/time.h> +#include <sys/limits.h> #include <err.h> #include <errno.h> @@ -116,6 +117,8 @@ struct dev { int fd; #define MAX_DSZS 16 struct dim sizes[MAX_DSZS]; +#define MAX_RATES 32 + int rates[MAX_DSZS][MAX_RATES]; int nsizes; int buf_type; }; @@ -157,6 +160,7 @@ struct video { int height; int bpf; int fps; + int nofps; #define M_IN_DEV 0x1 #define M_OUT_XV 0x2 #define M_IN_FILE 0x4 @@ -175,6 +179,7 @@ void display_event(struct video *); int dev_check_caps(struct video *); int dev_get_encs(struct video *); int dev_get_sizes(struct video *); +int dev_get_rates(struct video *); int dev_get_ctrls(struct video *); void dev_dump_info(struct video *); int dev_init(struct video *); @@ -808,6 +813,59 @@ dev_get_sizes(struct video *vid) } int +dev_get_rates(struct video *vid) +{ + struct dev *d = &vid->dev; + struct v4l2_frmivalenum ival; + struct v4l2_frmival_stepwise *s; + int i, j, num; + + for (i = 0; i < d->nsizes; i++) { + bzero(&ival, sizeof(ival)); + ival.pixel_format = encs[vid->enc].dev_id; + ival.width = d->sizes[i].w; + ival.height = d->sizes[i].h; + ival.index = 0; + while (ioctl(d->fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) != -1) { + switch(ival.type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + if (ival.index < MAX_RATES) { + d->rates[i][ival.index] = + ival.un.discrete.denominator / + ival.un.discrete.numerator; + } + break; + case V4L2_FRMIVAL_TYPE_CONTINUOUS: + case V4L2_FRMIVAL_TYPE_STEPWISE: + if (ival.index != 0) { + printf("invalid frame type!\n"); + return 0; + } + s = &ival.un.stepwise; + if (s->step.denominator != s->min.denominator || + s->step.denominator != s->max.denominator) { + printf("can't parse frame rate!\n"); + break; + } + for (num = s->min.numerator, j = 0; + num <= s->max.numerator && j < MAX_RATES; + num += s->step.numerator, j++) { + d->rates[i][j] = + s->step.denominator / num; + } + break; + default: + printf("invalid frame type!\n"); + return 0; + } + ival.index++; + } + } + + return 1; +} + +int dev_get_ctrls(struct video *vid) { struct dev *d = &vid->dev; @@ -927,13 +985,18 @@ dev_dump_info(struct video *vid) } fprintf(stderr, "\n"); - fprintf(stderr, " sizes: "); + fprintf(stderr, " frame sizes (width x height, in pixels) and rates (in frames per second):\n"); for (i = 0; i < d->nsizes; i++) { - if (i) - fprintf(stderr, ", "); - fprintf(stderr, "%dx%d", d->sizes[i].w, d->sizes[i].h); + fprintf(stderr, "\t%dx%d: ", d->sizes[i].w, d->sizes[i].h); + for (j = 0; j < MAX_RATES; j++) { + if (d->rates[i][j] == 0) + break; + if (j) + fprintf(stderr, ", "); + fprintf(stderr, "%d", d->rates[i][j]); + } + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); fprintf(stderr, " controls: "); for (i = 0, j = 0; i < CTRL_LAST; i++) { @@ -952,6 +1015,8 @@ dev_init(struct video *vid) { struct dev *d = &vid->dev; struct v4l2_format fmt; + struct v4l2_streamparm parm; + int fps; bzero(&fmt, sizeof(struct v4l2_format)); fmt.type = d->buf_type; @@ -969,6 +1034,29 @@ dev_init(struct video *vid) return 0; } + bzero(&parm, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (vid->fps) { + parm.parm.capture.timeperframe.numerator = 1; + parm.parm.capture.timeperframe.denominator = vid->fps; + } + if (ioctl(d->fd, VIDIOC_S_PARM, &parm) < 0) { + warn("VIDIOC_S_PARM"); + return 0; + } + + bzero(&parm, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(d->fd, VIDIOC_G_PARM, &parm) < 0) { + warn("VIDIOC_G_PARM"); + return 0; + } + fps = parm.parm.capture.timeperframe.denominator / + parm.parm.capture.timeperframe.numerator; + if (vid->fps && fps != vid->fps) + warnx("device returned %d fps, claimed support for %d fps", + fps, vid->fps); + return 1; } @@ -1033,7 +1121,7 @@ choose_size(struct video *vid) { struct xdsp *x = &vid->xdsp; struct dev *d = &vid->dev; - int i; + int i, j, diff, best, cur; if (vid->height && !vid->width) vid->width = vid->height * 4 / 3; @@ -1046,6 +1134,7 @@ choose_size(struct video *vid) if (vid->height > x->max_height) vid->height = x->max_height; } + if (vid->mode & M_IN_DEV) { i = 0; while (i < d->nsizes && @@ -1059,6 +1148,23 @@ choose_size(struct video *vid) i--; vid->width = d->sizes[i].w; vid->height = d->sizes[i].h; + + /* interval is a property of the frame */ + if (!vid->nofps) { + cur = j = 0; + best = INT_MAX; + while (j < MAX_RATES && d->rates[i][j]) { + diff = abs(vid->fps - d->rates[i][j]); + if (diff < best) { + best = diff; + cur = j; + if (diff == 0) + break; + } + j++; + } + vid->fps = d->rates[i][cur]; + } } return 1; @@ -1160,7 +1266,7 @@ setup(struct video *vid) return 0; if ((vid->mode & M_IN_DEV) && - (!dev_get_sizes(vid) || !dev_get_ctrls(vid))) + (!dev_get_sizes(vid) || !dev_get_rates(vid) || !dev_get_ctrls(vid))) return 0; if (!parse_size(vid) || !choose_size(vid)) @@ -1176,6 +1282,10 @@ setup(struct video *vid) fprintf(stderr, "using %s encoding\n", encs[vid->enc].name); fprintf(stderr, "using frame size %dx%d (%d bytes)\n", vid->width, vid->height, vid->bpf); + if (vid->fps) + fprintf(stderr, "using frame rate %d fps\n", vid->fps); + else + fprintf(stderr, "using default frame rate\n"); } if ((vid->frame_buffer = calloc(1, vid->bpf)) == NULL) { @@ -1217,7 +1327,7 @@ poll_input(struct video *vid) pfds[0].fd = (vid->mode & M_IN_FILE) ? vid->iofile_fd : vid->dev.fd; pfds[0].events = POLLIN; - ret = poll(pfds, 1, 0); + ret = poll(pfds, 1, INFTIM); if (ret != 1) return ret; @@ -1265,8 +1375,8 @@ grab_frame(struct video *vid) warnx("%s: EOF", vid->iofile); return 255; } - warn("%s", (vid->mode & M_IN_DEV) ? - vid->dev.path : vid->iofile); + warn("%s read %d/%d", (vid->mode & M_IN_DEV) ? + vid->dev.path : vid->iofile, done, vid->bpf); return 0; } @@ -1296,10 +1406,8 @@ stream(struct video *vid) long frames_played = -1, frames_grabbed = 0, fus = 50000; int sequence = 20, ret, err, todo, done; - if (vid->fps) + if (vid->fps && !vid->nofps) { fus = 1000000 / vid->fps; - - if (vid->fps) { timerclear(&frit.it_value); timerclear(&frit.it_interval); if (vid->fps == 1) { @@ -1325,23 +1433,25 @@ stream(struct video *vid) err = 0; ret = poll_input(vid); if (ret == 1) { - if (!vid->fps) - play = 1; if ((vid->mode & M_IN_DEV) || frames_grabbed - 1 == frames_played) { ret = grab_frame(vid); - if (ret == 1) + if (ret == 1) { frames_grabbed++; - else if (ret == 255) + if (vid->nofps) + play = 1; + } else if (ret == 255) break; else if (ret < 0) err++; } } else if (ret < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - err++; - warn("poll"); + /* continue if interrupted by play or shutdown signal */ + if (!((errno == EINTR || errno == EAGAIN) && + (play || shutdown))) { + err++; + warn("poll"); + } } else if (ret & (POLLERR | POLLHUP | POLLNVAL)) { if (!strcmp(vid->iofile, "-") && (ret & POLLHUP)) break; @@ -1355,12 +1465,12 @@ stream(struct video *vid) display_event(vid); if (shutdown) break; + if (hold || ((vid->mode & M_IN_FILE) && !play)) + usleep(fus); if (frames_grabbed < 1) play = 0; - if (hold || !play) { - usleep(fus / 5); + if (hold || !play) continue; - } play = 0; src = vid->frame_buffer; @@ -1397,7 +1507,8 @@ stream(struct video *vid) return 0; } } - frames_played++; + if (frames_grabbed > 0) + frames_played++; if (frames_played == 0) gettimeofday(&tp_start, NULL); @@ -1499,7 +1610,7 @@ main(int argc, char *argv[]) vid.enc = -1; wout = 1; - while ((ch = getopt(argc, argv, "va:e:f:i:O:o:r:s:")) != -1) { + while ((ch = getopt(argc, argv, "vRa:e:f:i:O:o:r:s:")) != -1) { switch (ch) { case 'a': x->cur_adap = strtonum(optarg, 0, 4, &errstr); @@ -1541,6 +1652,9 @@ main(int argc, char *argv[]) optarg); } break; + case 'R': + vid.nofps = 1; + break; case 'r': vid.fps = strtonum(optarg, 1, 100, &errstr); if (errstr != NULL) { @@ -1568,6 +1682,9 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; + if (vid.fps == 0) + vid.nofps = 1; + if (!setup(&vid)) cleanup(&vid, 1); |