---
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 189 +++++++++++++++++++++++++++++++++-
 1 file changed, 188 insertions(+), 1 deletion(-)

diff --git a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp 
b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
index f8e782d..b86c467 100644
--- a/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-streaming.cpp
@@ -1058,12 +1058,199 @@ void streaming_set_out(int fd)
                fclose(fin);
 }
 
+enum stream_type {
+       CAP,
+       OUT,
+};
+
+void streaming_set_m2m(int fd)
+{
+       int fd_flags = fcntl(fd, F_GETFL);
+       bool use_poll = options[OptStreamPoll];
+
+       bool is_mplane = capabilities &
+                       (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+                                V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+                                V4L2_CAP_VIDEO_M2M_MPLANE);
+       unsigned num_planes = 1;
+       bool is_mmap = options[OptStreamMmap];
+
+       __u32 type[2];
+       FILE *file[2] = {NULL, NULL};
+       struct v4l2_requestbuffers reqbufs[2];
+
+       type[CAP] = is_mplane ?
+               V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : 
V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       type[OUT] = is_mplane ?
+               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+       memset(&reqbufs, 0, sizeof(reqbufs));
+
+       reqbufs[CAP].count = reqbufs_count;
+       reqbufs[CAP].type = type[CAP];
+       reqbufs[CAP].memory = is_mmap ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+
+       reqbufs[OUT].count = reqbufs_count;
+       reqbufs[OUT].type = type[OUT];
+       reqbufs[OUT].memory = is_mmap ? V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
+
+       struct v4l2_event_subscription sub;
+
+       memset(&sub, 0, sizeof(sub));
+       sub.type = V4L2_EVENT_EOS;
+       ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
+
+       if (file_cap) {
+               if (!strcmp(file_cap, "-"))
+                       file[CAP] = stdout;
+               else
+                       file[CAP] = fopen(file_cap, "w+");
+       }
+
+       if (file_out) {
+               if (!strcmp(file_out, "-"))
+                       file[OUT] = stdin;
+               else
+                       file[OUT] = fopen(file_out, "r");
+       }
+
+       if (doioctl(fd, VIDIOC_REQBUFS, &reqbufs[CAP]) ||
+           doioctl(fd, VIDIOC_REQBUFS, &reqbufs[OUT]))
+               return;
+
+       void *buffers[2][reqbufs_count * VIDEO_MAX_PLANES];
+       unsigned buffer_lengths[2][reqbufs_count * VIDEO_MAX_PLANES];
+
+       do_setup_cap_buffers(fd, &reqbufs[CAP], is_mplane, num_planes,
+                            is_mmap, buffers[CAP], buffer_lengths[CAP]);
+
+       do_setup_out_buffers(fd, &reqbufs[OUT], is_mplane, num_planes,
+                            is_mmap, buffers[OUT], buffer_lengths[OUT],
+                            file[OUT]);
+
+       if (doioctl(fd, VIDIOC_STREAMON, &type[CAP]) ||
+           doioctl(fd, VIDIOC_STREAMON, &type[OUT]))
+               return;
+
+       if (use_poll)
+               fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK);
+
+       unsigned count[2] = { 0, 0 };
+       unsigned last[2] = { 0, 0 };
+       struct timeval tv_last[2];
+       bool eos[2] = { false, false};
+       fd_set read_fds;
+       fd_set write_fds;
+       fd_set exception_fds;
+
+       while (!eos[CAP] || !eos[OUT]) {
+
+               int r;
+
+               if (use_poll) {
+                       struct timeval tv;
+
+                       FD_ZERO(&read_fds);
+                       FD_SET(fd, &read_fds);
+
+                       FD_ZERO(&write_fds);
+                       FD_SET(fd, &write_fds);
+
+                       FD_ZERO(&exception_fds);
+                       FD_SET(fd, &exception_fds);
+
+                       /* Timeout. */
+                       tv.tv_sec = 2;
+                       tv.tv_usec = 0;
+
+                       r = select(fd + 1, &read_fds, &write_fds, 
&exception_fds, &tv);
+
+                       if (r == -1) {
+                               if (EINTR == errno)
+                                       continue;
+                               fprintf(stderr, "select error: %s\n",
+                                       strerror(errno));
+                               return;
+                       }
+
+                       if (r == 0) {
+                               fprintf(stderr, "select timeout\n");
+                               return;
+                       }
+               }
+
+               if (FD_ISSET(fd, &exception_fds)) {
+                       struct v4l2_event ev;
+
+                       while (!ioctl(fd, VIDIOC_DQEVENT, &ev)) {
+
+                               if (ev.type != V4L2_EVENT_EOS)
+                                       continue;
+
+                               eos[CAP] = true;
+                               doioctl(fd, VIDIOC_STREAMOFF, &type[CAP]);
+                               break;
+                       }
+               }
+
+               if (!eos[CAP]) {
+                       if (FD_ISSET(fd, &read_fds)) {
+                               r  = do_handle_cap(fd, &reqbufs[CAP], 
is_mplane, num_planes,
+                                                  buffers[CAP], 
buffer_lengths[CAP], file[CAP],
+                                                  &count[CAP], &last[CAP], 
&tv_last[CAP]);
+                               if (r < 0) {
+                                       eos[CAP] = true;
+                                       doioctl(fd, VIDIOC_STREAMOFF, 
&type[CAP]);
+                               }
+                       }
+               }
+
+               if (!eos[OUT]) {
+                       if (FD_ISSET(fd, &write_fds)) {
+                               r  = do_handle_out(fd, &reqbufs[OUT], 
is_mplane, num_planes,
+                                                  buffers[OUT], 
buffer_lengths[OUT], file[OUT],
+                                                  &count[OUT], &last[OUT], 
&tv_last[OUT]);
+                               if (r < 0)  {
+                                       eos[OUT] = true;
+
+                                       if (options[OptDecoderCmd]) {
+                                               doioctl(fd, VIDIOC_DECODER_CMD, 
&dec_cmd);
+                                               options[OptDecoderCmd] = false;
+                                       }
+
+                                       doioctl(fd, VIDIOC_STREAMOFF, 
&type[OUT]);
+
+                               }
+                       }
+
+               }
+       }
+
+       fcntl(fd, F_SETFL, fd_flags);
+       fprintf(stderr, "\n");
+
+       do_release_buffers(&reqbufs[CAP], num_planes, is_mmap,
+                          buffers[CAP], buffer_lengths[CAP]);
+
+       do_release_buffers(&reqbufs[OUT], num_planes, is_mmap,
+                          buffers[OUT], buffer_lengths[OUT]);
+
+       if (file[CAP] && file[CAP] != stdout)
+               fclose(file[CAP]);
+
+       if (file[OUT] && file[OUT] != stdin)
+               fclose(file[OUT]);
+}
+
 void streaming_set(int fd)
 {
        bool do_cap = options[OptStreamMmap] || options[OptStreamUser];
        bool do_out = options[OptStreamOutMmap] || options[OptStreamOutUser];
 
-       if (do_cap)
+       if (do_cap && do_out)
+               streaming_set_m2m(fd);
+       else if (do_cap)
                streaming_set_cap(fd);
        else if (do_out)
                streaming_set_out(fd);
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to