[PATCH 2/2] v4l2-ctl: initial attempt to support M2M device streaming

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux