v4l2-ctl: add eos and decoder-stop support.
authorHans Verkuil <hans.verkuil@cisco.com>
Tue, 9 Apr 2013 06:46:49 +0000 (08:46 +0200)
committerHans Verkuil <hans.verkuil@cisco.com>
Tue, 9 Apr 2013 06:46:49 +0000 (08:46 +0200)
When dealing with compressed streams it is useful if the capture streaming
code would check for V4L2_EVENT_EOS and if the output streaming side would
be able to use a STOP DECODER command before calling STREAMOFF to give the
decoder the time to flush any pending data.

This patch adds support for that.

Thanks to Tzu-Jung Lee for testing this.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
utils/v4l2-ctl/v4l2-ctl-misc.cpp
utils/v4l2-ctl/v4l2-ctl-streaming.cpp
utils/v4l2-ctl/v4l2-ctl.cpp
utils/v4l2-ctl/v4l2-ctl.h

index da39dda..6857fff 100644 (file)
 
 #include "v4l2-ctl.h"
 
+struct v4l2_decoder_cmd dec_cmd; /* (try_)decoder_cmd */
+static struct v4l2_encoder_cmd enc_cmd; /* (try_)encoder_cmd */
 static struct v4l2_jpegcompression jpegcomp; /* jpeg compression */
 static struct v4l2_streamparm parm;    /* get/set parm */
-static struct v4l2_encoder_cmd enc_cmd; /* (try_)encoder_cmd */
-static struct v4l2_decoder_cmd dec_cmd; /* (try_)decoder_cmd */
 static double fps = 0;                 /* set framerate speed, in fps */
 static double output_fps = 0;          /* set framerate speed, in fps */
 
index a6ea8b3..c29565f 100644 (file)
@@ -530,6 +530,7 @@ void streaming_set(int fd)
 {
        if (options[OptStreamMmap] || options[OptStreamUser]) {
                struct v4l2_requestbuffers reqbufs;
+               struct v4l2_event_subscription sub;
                int fd_flags = fcntl(fd, F_GETFL);
                bool is_mplane = capabilities &
                        (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
@@ -545,6 +546,9 @@ void streaming_set(int fd)
                reqbufs.count = reqbufs_count;
                reqbufs.type = type;
                reqbufs.memory = is_mmap ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+               memset(&sub, 0, sizeof(sub));
+               sub.type = V4L2_EVENT_EOS;
+               ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
 
                if (file) {
                        if (!strcmp(file, "-"))
@@ -623,26 +627,30 @@ void streaming_set(int fd)
 
                unsigned count = 0, last = 0;
                struct timeval tv_last;
+               bool eos = false;
 
-               for (;;) {
+               while (!eos) {
                        struct v4l2_plane planes[VIDEO_MAX_PLANES];
                        struct v4l2_buffer buf;
+                       fd_set read_fds;
+                       fd_set exception_fds;
                        char ch = '.';
                        int ret;
 
                        if (use_poll) {
-                               fd_set fds;
                                struct timeval tv;
                                int r;
 
-                               FD_ZERO(&fds);
-                               FD_SET(fd, &fds);
+                               FD_ZERO(&read_fds);
+                               FD_SET(fd, &read_fds);
+                               FD_ZERO(&exception_fds);
+                               FD_SET(fd, &exception_fds);
 
                                /* Timeout. */
                                tv.tv_sec = 2;
                                tv.tv_usec = 0;
 
-                               r = select(fd + 1, &fds, NULL, NULL, &tv);
+                               r = select(fd + 1, &read_fds, NULL, &exception_fds, &tv);
 
                                if (r == -1) {
                                        if (EINTR == errno)
@@ -658,6 +666,19 @@ void streaming_set(int fd)
                                }
                        }
 
+                       if (FD_ISSET(fd, &exception_fds)) {
+                               struct v4l2_event ev;
+
+                               while (!ioctl(fd, VIDIOC_DQEVENT, &ev)) {
+                                       if (ev.type != V4L2_EVENT_EOS)
+                                               continue;
+                                       eos = true;
+                                       break;
+                               }
+                       }
+                       if (!FD_ISSET(fd, &read_fds))
+                               continue;
+
                        memset(&buf, 0, sizeof(buf));
                        memset(planes, 0, sizeof(planes));
                        buf.type = reqbufs.type;
@@ -953,6 +974,10 @@ void streaming_set(int fd)
                        if (--stream_count == 0)
                                break;
                }
+               if (options[OptDecoderCmd]) {
+                       doioctl(fd, VIDIOC_DECODER_CMD, &dec_cmd);
+                       options[OptDecoderCmd] = false;
+               }
                doioctl(fd, VIDIOC_STREAMOFF, &type);
                fcntl(fd, F_SETFL, fd_flags);
                fprintf(stderr, "\n");
index 6057cce..1601b10 100644 (file)
@@ -967,8 +967,8 @@ int main(int argc, char **argv)
        overlay_set(fd);
        vbi_set(fd);
        selection_set(fd);
-       misc_set(fd);
        streaming_set(fd);
+       misc_set(fd);
 
        /* Get options */
 
index 8d6d50d..146dbe7 100644 (file)
@@ -264,6 +264,8 @@ void selection_set(int fd);
 void selection_get(int fd);
 
 // v4l2-ctl-misc.cpp
+// This one is also used by the streaming code.
+extern struct v4l2_decoder_cmd dec_cmd;
 void misc_usage(void);
 void misc_cmd(int ch, char *optarg);
 void misc_set(int fd);