On Wed April 10 2013 07:35:35 Tzu-Jung Lee wrote: > --- > 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); This should only check for V4L2_CAP_VIDEO_M2M_MPLANE. Only if that is set is M2M valid. I think it is probably a good idea to add some capability checks to each streaming_set_*() function checking up front whether the device supports that particular streaming option. > + unsigned num_planes = 1; num_planes may differ between capture and output, so this should be num_planes[2] = { 1, 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; Capture and output can have different reqbufs_count values. That static needs to be split up in a capture and output variant. > + 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}; No. eos is valid for the capture only. There is no eos[OUT]. > + 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]); > + Rather than using eos[OUT], just 'break' out of the loop here. > + } > + } > + > + } > + } > + > + 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); > Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html