Skip to contentSkip to conversation

source change support in v4l2-ctl

PATCH In review Dafna Hirschfeld 2 participants 7 messages Jan 21, 2019 – Jan 28, 2019 Media (V4L/DVB)

lore
Share & tools
lore
#0 lore raw

v2 cover source change support in v4l2-ctl

Changes from v2:
1. reomve the patch "test the excpetion fds first in streaming_set_m2m" instead check the last buffer at the end of each loop.
2. The fmt shoud not be queried with g_fmt at each iteration, but only after a resolution change.
3. don't enum/get/set the new format in "Introduce capture_setup" patch

Dafna Hirschfeld (5):
v4l2-ctl: Add support for crop and compose selection in streaming
v4l2-ctl: Add function get_codec_type
v4l2-ctl: Introduce capture_setup
v4l2-ctl: Add support for source change event for m2m decoder
v4l2-ctl: Add --stream-pixformat option

 utils/common/codec-fwht.patch         |   8 +-
 utils/common/v4l-stream.c             |  14 +-
 utils/common/v4l-stream.h             |   6 +-
 utils/qvidcap/capture.cpp             |   2 +
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 363 +++++++++++++++++++++++---
 utils/v4l2-ctl/v4l2-ctl.cpp           |  39 ++-
 utils/v4l2-ctl/v4l2-ctl.h             |   2 +
 7 files changed, 375 insertions(+), 59 deletions(-)
Signature · 1 line
2.17.1
#1 lore raw

PATCH v2 1/5 v4l2-ctl: Add support for crop and compose selection in streaming

Support crop and compose selection.
If the driver supports crop/compose then the raw frame is arranged inside a padded buffer.

---
 utils/common/codec-fwht.patch         |   8 +-
 utils/common/v4l-stream.c             |  14 +--
 utils/common/v4l-stream.h             |   6 +-
 utils/qvidcap/capture.cpp             |   2 +
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 141 ++++++++++++++++++++++++--
 5 files changed, 150 insertions(+), 21 deletions(-)
utils/common/codec-fwht.patch +5 -3
index 4d41225b..37ac4672 100644
@@ -1,6 +1,6 @@
---- a/utils/common/codec-fwht.h.old	2018-11-23 13:43:52.713731559 +0100
-+++ b/utils/common/codec-fwht.h	2018-11-23 13:47:55.484198283 +0100
-@@ -8,8 +8,24 @@
+--- a/utils/common/codec-fwht.h.old	2018-12-29 11:23:58.128328613 -0800
++++ b/utils/common/codec-fwht.h	2018-12-29 11:24:16.099127560 -0800
+@@ -8,8 +8,26 @@
  #define CODEC_FWHT_H
  
  #include <linux/types.h>
@@ -17,6 +17,8 @@
 +#define GENMASK(h, l) \
 +	(((~0UL) - (1UL << (l)) + 1) & (~0UL >> ((8 * sizeof(long)) - 1 - (h))))
 +#define pr_err(arg...)
++#define __round_mask(x, y) ((__typeof__(x))((y)-1))
++#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
 +
 +
 +typedef __u32 u32;
utils/common/v4l-stream.c +8 -6
index 9f842e21..a1cabadb 100644
@@ -171,25 +171,28 @@ unsigned rle_compress(__u8 *b, unsigned size, unsigned bpl)
 	return (__u8 *)dst - b;
 }
 
-struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned w, unsigned h,
+struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned visible_width, unsigned visible_height,
+			     unsigned coded_width, unsigned coded_height,
 			     unsigned field, unsigned colorspace, unsigned xfer_func,
 			     unsigned ycbcr_enc, unsigned quantization)
 {
 	struct codec_ctx *ctx;
 	const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_find_pixfmt(pixfmt);
 	unsigned int chroma_div;
-	unsigned int size = w * h;
+	unsigned int size = coded_width * coded_height;
 
 	// fwht expects macroblock alignment, check can be dropped once that
 	// restriction is lifted.
-	if (!info || w % 8 || h % 8)
+	if (!info || coded_width % 8 || coded_height % 8)
 		return NULL;
 
 	ctx = malloc(sizeof(*ctx));
 	if (!ctx)
 		return NULL;
-	ctx->state.width = w;
-	ctx->state.height = h;
+	ctx->state.coded_width = coded_width;
+	ctx->state.coded_height = coded_height;
+	ctx->state.visible_width = visible_width;
+	ctx->state.visible_height = visible_height;
 	ctx->state.info = info;
 	ctx->field = field;
 	ctx->state.colorspace = colorspace;
@@ -208,7 +211,6 @@ struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned w, unsigned h,
 		free(ctx);
 		return NULL;
 	}
-	ctx->state.ref_frame.width = ctx->state.ref_frame.height = 0;
 	ctx->state.ref_frame.cb = ctx->state.ref_frame.luma + size;
 	ctx->state.ref_frame.cr = ctx->state.ref_frame.cb + size / chroma_div;
 	ctx->state.ref_frame.alpha = ctx->state.ref_frame.cr + size / chroma_div;
utils/common/v4l-stream.h +4 -2
index c235150b..fe5dfe90 100644
@@ -9,12 +9,13 @@
 #define _V4L_STREAM_H_
 
 #include <linux/videodev2.h>
-#include <codec-v4l2-fwht.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
+#include <codec-v4l2-fwht.h>
+
 /* Default port */
 #define V4L_STREAM_PORT 8362
 
@@ -145,7 +146,8 @@ struct codec_ctx {
 
 unsigned rle_compress(__u8 *buf, unsigned size, unsigned bytesperline);
 void rle_decompress(__u8 *buf, unsigned size, unsigned rle_size, unsigned bytesperline);
-struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned w, unsigned h, unsigned field,
+struct codec_ctx *fwht_alloc(unsigned pixfmt, unsigned visible_width, unsigned visible_height,
+			     unsigned coded_width, unsigned coded_height, unsigned field,
 			     unsigned colorspace, unsigned xfer_func, unsigned ycbcr_enc,
 			     unsigned quantization);
 void fwht_free(struct codec_ctx *ctx);
utils/qvidcap/capture.cpp +2 -0
index 8c11ac53..e04db6be 100644
@@ -749,6 +749,7 @@ void CaptureWin::setModeSocket(int socket, int port)
 	if (m_ctx)
 		free(m_ctx);
 	m_ctx = fwht_alloc(m_v4l_fmt.g_pixelformat(), m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
+			   m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
 			   m_v4l_fmt.g_field(), m_v4l_fmt.g_colorspace(), m_v4l_fmt.g_xfer_func(),
 			   m_v4l_fmt.g_ycbcr_enc(), m_v4l_fmt.g_quantization());
 
@@ -1114,6 +1115,7 @@ void CaptureWin::listenForNewConnection()
 	if (m_ctx)
 		free(m_ctx);
 	m_ctx = fwht_alloc(fmt.g_pixelformat(), fmt.g_width(), fmt.g_height(),
+			   fmt.g_width(), fmt.g_height(),
 			   fmt.g_field(), fmt.g_colorspace(), fmt.g_xfer_func(),
 			   fmt.g_ycbcr_enc(), fmt.g_quantization());
 	setPixelAspect(pixelaspect);
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +131 -10

235 lines not on this page · raw message

Signature · 1 line
2.17.1
#2 lore raw

PATCH v2 2/5 v4l2-ctl: Add function get_codec_type

In reply to Dafna Hirschfeld

Add function get_codec_type that returns the type
of codec NOT_CODEC/ENCODER/DEOCDER.
Move the functions get_cap_compose/crop_rect
to the start of the file.

---
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 123 ++++++++++++++++++--------
 1 file changed, 85 insertions(+), 38 deletions(-)
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +85 -38
index 8a98b6bd..1383c5f2 100644
@@ -82,6 +82,12 @@ static bool support_out_crop;
 #define TS_WINDOW 241
 #define FILE_HDR_ID			v4l2_fourcc('V', 'h', 'd', 'r')
 
+enum codec_type {
+	NOT_CODEC,
+	ENCODER,
+	DECODER
+};
+
 class fps_timestamps {
 private:
 	unsigned idx;
@@ -334,6 +340,85 @@ void streaming_usage(void)
 	       	V4L_STREAM_PORT);
 }
 
+static enum codec_type get_codec_type(cv4l_fd &fd)
+{
+	struct v4l2_fmtdesc fmt_desc;
+	int num_cap_fmts = 0;
+	int num_compressed_cap_fmts = 0;
+	int num_out_fmts = 0;
+	int num_compressed_out_fmts = 0;
+
+	if (!fd.has_vid_m2m())
+		return NOT_CODEC;
+
+	if (fd.enum_fmt(fmt_desc, true, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE))
+		return NOT_CODEC;
+
+	do {
+		if (fmt_desc.flags & V4L2_FMT_FLAG_COMPRESSED)
+			num_compressed_cap_fmts++;
+		num_cap_fmts++;
+	} while (!fd.enum_fmt(fmt_desc));
+
+
+	if (fd.enum_fmt(fmt_desc, true, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT))
+		return NOT_CODEC;
+
+	do {
+		if (fmt_desc.flags & V4L2_FMT_FLAG_COMPRESSED)
+			num_compressed_out_fmts++;
+		num_out_fmts++;
+	} while (!fd.enum_fmt(fmt_desc));
+
+	if (num_compressed_out_fmts == 0 && num_compressed_cap_fmts == num_cap_fmts) {
+		return ENCODER;
+	}
+
+	if (num_compressed_cap_fmts == 0 && num_compressed_out_fmts == num_out_fmts) {
+		return DECODER;
+	}
+
+	return NOT_CODEC;
+}
+
+static int get_cap_compose_rect(cv4l_fd &fd)
+{
+	v4l2_selection sel;
+
+	memset(&sel, 0, sizeof(sel));
+	sel.type = vidcap_buftype;
+	sel.target = V4L2_SEL_TGT_COMPOSE;
+
+	if (fd.g_selection(sel) == 0) {
+		support_cap_compose = true;
+		composed_width = sel.r.width;
+		composed_height = sel.r.height;
+		return 0;
+	}
+
+	support_cap_compose = false;
+	return 0;
+}
+
+static int get_out_crop_rect(cv4l_fd &fd)
+{
+	v4l2_selection sel;
+
+	memset(&sel, 0, sizeof(sel));
+	sel.type = vidout_buftype;
+	sel.target = V4L2_SEL_TGT_CROP;
+
+	if (fd.g_selection(sel) == 0) {
+		support_out_crop = true;
+		cropped_width = sel.r.width;
+		cropped_height = sel.r.height;
+		return 0;
+	}
+
+	support_out_crop = false;
+	return 0;
+}
+
 static void set_time_stamp(cv4l_buffer &buf)
 {
 	if ((buf.g_flags() & V4L2_BUF_FLAG_TIMESTAMP_MASK) != V4L2_BUF_FLAG_TIMESTAMP_COPY)
@@ -2109,44 +2194,6 @@ done:
 		fclose(file[OUT]);
 }
 
-static int get_cap_compose_rect(cv4l_fd &fd)
-{
-	v4l2_selection sel;
-
-	memset(&sel, 0, sizeof(sel));
-	sel.type = vidcap_buftype;
-	sel.target = V4L2_SEL_TGT_COMPOSE;
-
-	if (fd.g_selection(sel) == 0) {
-		support_cap_compose = true;
-		composed_width = sel.r.width;
-		composed_height = sel.r.height;
-		return 0;
-	}
-
-	support_cap_compose = false;
-	return 0;
-}
-
-static int get_out_crop_rect(cv4l_fd &fd)
-{
-	v4l2_selection sel;
-
-	memset(&sel, 0, sizeof(sel));
-	sel.type = vidout_buftype;
-	sel.target = V4L2_SEL_TGT_CROP;
-
-	if (fd.g_selection(sel) == 0) {
-		support_out_crop = true;
-		cropped_width = sel.r.width;
-		cropped_height = sel.r.height;
-		return 0;
-	}
-
-	support_out_crop = false;
-	return 0;
-}
-
 void streaming_set(cv4l_fd &fd, cv4l_fd &out_fd)
 {
 	cv4l_disable_trace dt(fd);
Signature · 1 line
2.17.1
#3 lore raw

PATCH v2 3/5 v4l2-ctl: Introduce capture_setup

In reply to Dafna Hirschfeld

Add function capture_setup that implements the
capture setup sequence.

---
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 46 ++++++++++++++++++++++-----
 1 file changed, 38 insertions(+), 8 deletions(-)
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +38 -8
index 1383c5f2..d74a6c0b 100644
@@ -1833,6 +1833,36 @@ enum stream_type {
 	OUT,
 };
 
+static int capture_setup(cv4l_fd &fd, cv4l_queue &in)
+{
+	if (fd.streamoff(in.g_type())) {
+		fprintf(stderr, "%s: fd.streamoff error\n", __func__);
+		return -1;
+	}
+	get_cap_compose_rect(fd);
+
+	/* release any buffer allocated */
+	if (in.reqbufs(&fd)) {
+		fprintf(stderr, "%s: in.reqbufs 0 error\n", __func__);
+		return -1;
+	}
+
+	if (in.reqbufs(&fd, reqbufs_count_cap)) {
+		fprintf(stderr, "%s: in.reqbufs %u error\n", __func__,
+			reqbufs_count_cap);
+		return -1;
+	}
+	if (in.obtain_bufs(&fd) || in.queue_all(&fd)) {
+		fprintf(stderr, "%s: in.obtain_bufs error\n", __func__);
+		return -1;
+	}
+	if (fd.streamon(in.g_type())) {
+		fprintf(stderr, "%s: fd.streamon error\n", __func__);
+		return -1;
+	}
+	return 0;
+}
+
 static void streaming_set_m2m(cv4l_fd &fd)
 {
 	int fd_flags = fcntl(fd.g_fd(), F_GETFL);
@@ -1897,21 +1927,21 @@ static void streaming_set_m2m(cv4l_fd &fd)
 		}
 	}
 
-	if (in.reqbufs(&fd, reqbufs_count_cap) ||
-	    out.reqbufs(&fd, reqbufs_count_out))
+	if (out.reqbufs(&fd, reqbufs_count_out))
 		goto done;
 
-	if (in.obtain_bufs(&fd) ||
-	    in.queue_all(&fd) ||
-	    do_setup_out_buffers(fd, out, file[OUT], true))
+	if (do_setup_out_buffers(fd, out, file[OUT], true))
 		goto done;
 
-	fps_ts[CAP].determine_field(fd.g_fd(), in.g_type());
-	fps_ts[OUT].determine_field(fd.g_fd(), out.g_type());
+	if (fd.streamon(out.g_type()))
+		goto done;
 
-	if (fd.streamon(in.g_type()) || fd.streamon(out.g_type()))
+	if (capture_setup(fd, in))
 		goto done;
 
+	fps_ts[CAP].determine_field(fd.g_fd(), in.g_type());
+	fps_ts[OUT].determine_field(fd.g_fd(), out.g_type());
+
 	while (stream_sleep == 0)
 		sleep(100);
 
Signature · 1 line
2.17.1
#4 lore raw

PATCH v2 4/5 v4l2-ctl: Add support for source change event for m2m decoder

In reply to Dafna Hirschfeld

Subscribe to source change event.
The capture setup sequence is executed only due to a change event.

---
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 112 +++++++++++++++++++-------
 1 file changed, 85 insertions(+), 27 deletions(-)
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +85 -27
index d74a6c0b..8d034b85 100644
@@ -78,6 +78,7 @@ static unsigned int composed_width;
 static unsigned int composed_height;
 static bool support_cap_compose;
 static bool support_out_crop;
+static bool in_source_change_event;
 
 #define TS_WINDOW 241
 #define FILE_HDR_ID			v4l2_fourcc('V', 'h', 'd', 'r')
@@ -752,7 +753,8 @@ static void read_write_padded_frame(cv4l_fmt &fmt, unsigned char *buf,
 				    FILE *fpointer, unsigned &sz,
 				    unsigned &len, bool is_read)
 {
-	const struct v4l2_fwht_pixfmt_info *vic_fmt = v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
+	const struct v4l2_fwht_pixfmt_info *vic_fmt =
+			v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
 	unsigned coded_height = fmt.g_height();
 	unsigned real_width;
 	unsigned real_height;
@@ -801,7 +803,8 @@ static void read_write_padded_frame(cv4l_fmt &fmt, unsigned char *buf,
 	}
 }
 
-static bool fill_buffer_from_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &b, FILE *fin)
+static bool fill_buffer_from_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &b,
+				  cv4l_fmt &fmt, FILE *fin)
 {
 	static bool first = true;
 	static bool is_fwht = false;
@@ -1059,7 +1062,7 @@ static int do_setup_out_buffers(cv4l_fd &fd, cv4l_queue &q, FILE *fin, bool qbuf
 					tpg_fillbuffer(&tpg, stream_out_std, j, (u8 *)q.g_dataptr(i, j));
 			}
 		}
-		if (fin && !fill_buffer_from_file(fd, q, buf, fin))
+		if (fin && !fill_buffer_from_file(fd, q, buf, fmt, fin))
 			return -2;
 
 		if (qbuf) {
@@ -1077,7 +1080,8 @@ static int do_setup_out_buffers(cv4l_fd &fd, cv4l_queue &q, FILE *fin, bool qbuf
 	return 0;
 }
 
-static void write_buffer_to_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &buf, FILE *fout)
+static void write_buffer_to_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &buf,
+				 cv4l_fmt &fmt, FILE *fout)
 {
 #ifndef NO_STREAM_TO
 	unsigned comp_size[VIDEO_MAX_PLANES];
@@ -1118,9 +1122,7 @@ static void write_buffer_to_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &buf, F
 		__u32 used = buf.g_bytesused();
 		unsigned offset = buf.g_data_offset();
 		unsigned sz;
-		cv4l_fmt fmt;
 
-		fd.g_fmt(fmt, q.g_type());
 		if (offset > used) {
 			// Should never happen
 			fprintf(stderr, "offset %d > used %d!\n",
@@ -1153,7 +1155,7 @@ static void write_buffer_to_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &buf, F
 }
 
 static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
-			 unsigned &count, fps_timestamps &fps_ts)
+			 unsigned &count, fps_timestamps &fps_ts, cv4l_fmt &fmt)
 {
 	char ch = '<';
 	int ret;
@@ -1192,7 +1194,7 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
 
 	if (fout && (!stream_skip || ignore_count_skip) &&
 	    buf.g_bytesused(0) && !(buf.g_flags() & V4L2_BUF_FLAG_ERROR))
-		write_buffer_to_file(fd, q, buf, fout);
+		write_buffer_to_file(fd, q, buf, fmt, fout);
 
 	if (buf.g_flags() & V4L2_BUF_FLAG_KEYFRAME)
 		ch = 'K';
@@ -1205,8 +1207,18 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
 				     host_fd_to >= 0 ? 100 - comp_perc / comp_perc_count : -1);
 		comp_perc_count = comp_perc = 0;
 	}
-	if (!last_buffer && index == NULL && fd.qbuf(buf))
-		return -1;
+	if (!last_buffer && index == NULL) {
+		/*
+		 * EINVAL in qbuf can happen if this is the last buffer before
+		 * a dynamic resolution change sequence. In this case the buffer
+		 * has the size that fits the old resolution and might not
+		 * fit to the new one.
+		 */
+		if (fd.qbuf(buf) && errno != EINVAL) {
+			fprintf(stderr, "%s: qbuf error\n", __func__);
+			return -1;
+		}
+	}
 	if (index)
 		*index = buf.g_index();
 
@@ -1246,7 +1258,7 @@ static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
 }
 
 static int do_handle_out(cv4l_fd &fd, cv4l_queue &q, FILE *fin, cv4l_buffer *cap,
-			 unsigned &count, fps_timestamps &fps_ts)
+			 unsigned &count, fps_timestamps &fps_ts, cv4l_fmt fmt)
 {
 	cv4l_buffer buf(q);
 	int ret = 0;
@@ -1291,7 +1303,7 @@ static int do_handle_out(cv4l_fd &fd, cv4l_queue &q, FILE *fin, cv4l_buffer *cap
 			output_field = V4L2_FIELD_TOP;
 	}
 
-	if (fin && !fill_buffer_from_file(fd, q, buf, fin))
+	if (fin && !fill_buffer_from_file(fd, q, buf, fmt, fin))
 		return -2;
 
 	if (!fin && stream_out_refresh) {
@@ -1365,6 +1377,9 @@ static void streaming_set_cap(cv4l_fd &fd)
 	bool eos;
 	bool source_change;
 	FILE *fout = NULL;
+	cv4l_fmt fmt;
+
+	fd.g_fmt(fmt);
 
 	if (!(capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE |
 			      V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
@@ -1573,7 +1588,7 @@ recover:
 
 		if (FD_ISSET(fd.g_fd(), &read_fds)) {
 			r = do_handle_cap(fd, q, fout, NULL,
-					   count, fps_ts);
+					   count, fps_ts, fmt);
 			if (r == -1)
 				break;
 		}
@@ -1605,6 +1620,9 @@ static void streaming_set_out(cv4l_fd &fd)
 	fps_timestamps fps_ts;
 	unsigned count = 0;
 	FILE *fin = NULL;
+	cv4l_fmt fmt;
+
+	fd.g_fmt(fmt);
 
 	if (!(capabilities & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
 			      V4L2_CAP_VBI_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT |
@@ -1806,7 +1824,7 @@ static void streaming_set_out(cv4l_fd &fd)
 			}
 		}
 		r = do_handle_out(fd, q, fin, NULL,
-				   count, fps_ts);
+				   count, fps_ts, fmt);
 		if (r == -1)
 			break;
 
@@ -1875,6 +1893,11 @@ static void streaming_set_m2m(cv4l_fd &fd)
 	fd_set *rd_fds = &fds[0]; /* for capture */
 	fd_set *ex_fds = &fds[1]; /* for capture */
 	fd_set *wr_fds = &fds[2]; /* for output */
+	bool cap_streaming = false;
+	cv4l_fmt fmt[2];
+
+	fd.g_fmt(fmt[OUT], out.g_type());
+	fd.g_fmt(fmt[CAP], in.g_type());
 
 	if (!fd.has_vid_m2m()) {
 		fprintf(stderr, "unsupported m2m stream type\n");
@@ -1897,6 +1920,10 @@ static void streaming_set_m2m(cv4l_fd &fd)
 
 	bool have_eos = !fd.subscribe_event(sub);
 	bool is_encoder = false;
+	enum codec_type codec_type = get_codec_type(fd);
+
+	if (codec_type == NOT_CODEC)
+		goto done;
 
 	if (have_eos) {
 		cv4l_fmt fmt(in.g_type());
@@ -1905,6 +1932,11 @@ static void streaming_set_m2m(cv4l_fd &fd)
 		is_encoder = !fmt.g_bytesperline();
 	}
 
+	memset(&sub, 0, sizeof(sub));
+	sub.type = V4L2_EVENT_SOURCE_CHANGE;
+	if (fd.subscribe_event(sub))
+		goto done;
+
 	if (file_to) {
 		if (!strcmp(file_to, "-"))
 			file[CAP] = stdout;
@@ -1936,8 +1968,9 @@ static void streaming_set_m2m(cv4l_fd &fd)
 	if (fd.streamon(out.g_type()))
 		goto done;
 
-	if (capture_setup(fd, in))
-		goto done;
+	if (codec_type == ENCODER)
+		if (capture_setup(fd, in))
+			goto done;
 
 	fps_ts[CAP].determine_field(fd.g_fd(), in.g_type());
 	fps_ts[OUT].determine_field(fd.g_fd(), out.g_type());
@@ -1982,7 +2015,7 @@ static void streaming_set_m2m(cv4l_fd &fd)
 
 		if (rd_fds && FD_ISSET(fd.g_fd(), rd_fds)) {
 			r = do_handle_cap(fd, in, file[CAP], NULL,
-					  count[CAP], fps_ts[CAP]);
+					  count[CAP], fps_ts[CAP], fmt[CAP]);
 			if (r < 0) {
 				rd_fds = NULL;
 				if (!have_eos) {
@@ -1990,13 +2023,11 @@ static void streaming_set_m2m(cv4l_fd &fd)
 					break;
 				}
 			}
-			if (last_buffer)
-				break;
 		}
 
 		if (wr_fds && FD_ISSET(fd.g_fd(), wr_fds)) {
 			r = do_handle_out(fd, out, file[OUT], NULL,
-					  count[OUT], fps_ts[OUT]);
+					  count[OUT], fps_ts[OUT], fmt[OUT]);
 			if (r < 0)  {
 				wr_fds = NULL;
 
@@ -2022,11 +2053,35 @@ static void streaming_set_m2m(cv4l_fd &fd)
 			struct v4l2_event ev;
 
 			while (!fd.dqevent(ev)) {
-				if (ev.type != V4L2_EVENT_EOS)
-					continue;
-				wr_fds = NULL;
-				fprintf(stderr, "EOS");
-				fflush(stderr);
+				if (ev.type == V4L2_EVENT_EOS) {
+					wr_fds = NULL;
+					fprintf(stderr, "EOS");
+					fflush(stderr);
+				} else if (ev.type == V4L2_EVENT_SOURCE_CHANGE) {
+					fprintf(stderr, "SOURCE CHANGE\n");
+					in_source_change_event = true;
+
+					/*
+					 * if capture is not streaming, the
+					 * driver will not send a last buffer so
+					 * we set it here
+					 */
+					if (!cap_streaming)
+						last_buffer = true;
+				}
+			}
+		}
+
+		if (last_buffer) {
+			if (in_source_change_event) {
+				in_source_change_event = false;
+				last_buffer = false;
+				if (capture_setup(fd, in))
+					goto done;
+				fd.g_fmt(fmt[OUT], out.g_type());
+				fd.g_fmt(fmt[CAP], in.g_type());
+				cap_streaming = true;
+			} else {
 				break;
 			}
 		}
@@ -2063,7 +2118,10 @@ static void streaming_set_cap2out(cv4l_fd &fd, cv4l_fd &out_fd)
 	FILE *file[2] = {NULL, NULL};
 	fd_set fds;
 	unsigned cnt = 0;
+	cv4l_fmt fmt[2];
 
+	fd.g_fmt(fmt[OUT], out.g_type());
+	fd.g_fmt(fmt[CAP], in.g_type());
 	if (!(capabilities & (V4L2_CAP_VIDEO_CAPTURE |
 			      V4L2_CAP_VIDEO_CAPTURE_MPLANE |
 			      V4L2_CAP_VIDEO_M2M |
@@ -2179,7 +2237,7 @@ static void streaming_set_cap2out(cv4l_fd &fd, cv4l_fd &out_fd)
 			int index = -1;
 
 			r = do_handle_cap(fd, in, file[CAP], &index,
-					   count[CAP], fps_ts[CAP]);
+					  count[CAP], fps_ts[CAP], fmt[CAP]);
 			if (r)
 				fprintf(stderr, "handle cap %d\n", r);
 			if (!r) {
@@ -2188,7 +2246,7 @@ static void streaming_set_cap2out(cv4l_fd &fd, cv4l_fd &out_fd)
 				if (fd.querybuf(buf))
 					break;
 				r = do_handle_out(out_fd, out, file[OUT], &buf,
-					   count[OUT], fps_ts[OUT]);
+						  count[OUT], fps_ts[OUT], fmt[OUT]);
 			}
 			if (r)
 				fprintf(stderr, "handle out %d\n", r);
Signature · 1 line
2.17.1
#5 lore raw

PATCH v2 5/5 v4l2-ctl: Add --stream-pixformat option

In reply to Dafna Hirschfeld

This option sets the capture pixelformat in the capture setup sequence.
If the format is not supported decoding will stop. If the option is not given then the default is to set the first supported format.

---
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 37 +++++++++++++++++++++++++
 utils/v4l2-ctl/v4l2-ctl.cpp           | 39 ++++++++++++++++++---------
 utils/v4l2-ctl/v4l2-ctl.h             |  2 ++
 3 files changed, 65 insertions(+), 13 deletions(-)
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +37 -0
index 8d034b85..3e0a449c 100644
@@ -78,6 +78,7 @@ static unsigned int composed_width;
 static unsigned int composed_height;
 static bool support_cap_compose;
 static bool support_out_crop;
+static unsigned int cap_pixelformat;
 static bool in_source_change_event;
 
 #define TS_WINDOW 241
@@ -272,6 +273,10 @@ void streaming_usage(void)
 	       "  --stream-from <file>\n"
 	       "                     stream from this file. The default is to generate a pattern.\n"
 	       "                     If <file> is '-', then the data is read from stdin.\n"
+	       "  --stream-pixformat <pixformat>\n"
+	       "                     set the video pixelformat."
+	       "                     <pixelformat> is either the format index as reported by\n"
+	       "                     --list-formats-out, or the fourcc value as a string.\n"
 	       "  --stream-from-hdr <file> stream from this file. Same as --stream-from, but each\n"
 	       "                     frame is prefixed by a header. Use for compressed data.\n"
 	       "  --stream-from-host <hostname[:port]>\n"
@@ -606,8 +611,16 @@ void streaming_cmd(int ch, char *optarg)
 {
 	unsigned i;
 	int speed;
+	int r;
 
 	switch (ch) {
+	case OptStreamPixformat:
+		r = parse_pixelfmt(optarg, cap_pixelformat);
+		if (r) {
+			streaming_usage();
+			exit(1);
+		}
+		break;
 	case OptStreamCount:
 		stream_count = strtoul(optarg, 0L, 0);
 		break;
@@ -1853,6 +1866,9 @@ enum stream_type {
 
 static int capture_setup(cv4l_fd &fd, cv4l_queue &in)
 {
+	v4l2_fmtdesc fmt_desc;
+	cv4l_fmt fmt;
+
 	if (fd.streamoff(in.g_type())) {
 		fprintf(stderr, "%s: fd.streamoff error\n", __func__);
 		return -1;
@@ -1865,6 +1881,27 @@ static int capture_setup(cv4l_fd &fd, cv4l_queue &in)
 		return -1;
 	}
 
+	if (cap_pixelformat) {
+		if (fd.enum_fmt(fmt_desc, true, 0, in.g_type())) {
+			fprintf(stderr, "%s: fd.enum_fmt error\n", __func__);
+			return -1;
+		}
+
+		do {
+			if (cap_pixelformat == fmt_desc.pixelformat)
+				break;
+		} while (!fd.enum_fmt(fmt_desc));
+
+		if (cap_pixelformat != fmt_desc.pixelformat) {
+			fprintf(stderr, "%s: format from user not supported\n", __func__);
+			return -1;
+		}
+
+		fd.g_fmt(fmt, in.g_type());
+		fmt.s_pixelformat(cap_pixelformat);
+		fd.s_fmt(fmt, in.g_type());
+	}
+
 	if (in.reqbufs(&fd, reqbufs_count_cap)) {
 		fprintf(stderr, "%s: in.reqbufs %u error\n", __func__,
 			reqbufs_count_cap);
utils/v4l2-ctl/v4l2-ctl.cpp +26 -13
index 1783979d..2cbf519e 100644
@@ -238,6 +238,7 @@ static struct option long_options[] = {
 	{"list-buffers-sdr", no_argument, 0, OptListBuffersSdr},
 	{"list-buffers-sdr-out", no_argument, 0, OptListBuffersSdrOut},
 	{"list-buffers-meta", no_argument, 0, OptListBuffersMeta},
+	{"stream-pixformat", required_argument, 0, OptStreamPixformat},
 	{"stream-count", required_argument, 0, OptStreamCount},
 	{"stream-skip", required_argument, 0, OptStreamSkip},
 	{"stream-loop", no_argument, 0, OptStreamLoop},
@@ -722,6 +723,30 @@ __u32 parse_quantization(const char *s)
 	return V4L2_QUANTIZATION_DEFAULT;
 }
 
+int parse_pixelfmt(char *value,  __u32 &pixelformat)
+{
+	int fmts = 0;
+	bool be_pixfmt;
+
+	if(!value)
+		return -EINVAL;
+
+	be_pixfmt = strlen(value) == 7 && !memcmp(value + 4, "-BE", 3);
+	if (be_pixfmt)
+		value[4] = 0;
+	if (strlen(value) == 4) {
+		pixelformat =
+			v4l2_fourcc(value[0], value[1],
+					value[2], value[3]);
+		if (be_pixfmt)
+			pixelformat |= 1 << 31;
+	} else {
+		pixelformat = strtol(value, 0L, 0);
+	}
+	fmts |= FmtPixelFormat;
+	return 0;
+}
+
 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 	      __u32 &field, __u32 &colorspace, __u32 &xfer_func, __u32 &ycbcr,
 	      __u32 &quantization, __u32 &flags, __u32 *bytesperline)
@@ -729,7 +754,6 @@ int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 	char *value, *subs;
 	int fmts = 0;
 	unsigned bpl_index = 0;
-	bool be_pixfmt;
 
 	field = V4L2_FIELD_ANY;
 	flags = 0;
@@ -760,18 +784,7 @@ int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 			fmts |= FmtHeight;
 			break;
 		case 2:
-			be_pixfmt = strlen(value) == 7 && !memcmp(value + 4, "-BE", 3);
-			if (be_pixfmt)
-				value[4] = 0;
-			if (strlen(value) == 4) {
-				pixelformat =
-					v4l2_fourcc(value[0], value[1],
-							value[2], value[3]);
-				if (be_pixfmt)
-					pixelformat |= 1 << 31;
-			} else {
-				pixelformat = strtol(value, 0L, 0);
-			}
+			parse_pixelfmt(value, pixelformat);
 			fmts |= FmtPixelFormat;
 			break;
 		case 3:
utils/v4l2-ctl/v4l2-ctl.h +2 -0
index 5a52a0a4..8eee5351 100644
@@ -205,6 +205,7 @@ enum Option {
 	OptListBuffersSdr,
 	OptListBuffersSdrOut,
 	OptListBuffersMeta,
+	OptStreamPixformat,
 	OptStreamCount,
 	OptStreamSkip,
 	OptStreamLoop,
@@ -299,6 +300,7 @@ __u32 parse_xfer_func(const char *s);
 __u32 parse_ycbcr(const char *s);
 __u32 parse_hsv(const char *s);
 __u32 parse_quantization(const char *s);
+int parse_pixelfmt(char *value,  __u32 &pixelformat);
 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 	      __u32 &field, __u32 &colorspace, __u32 &xfer, __u32 &ycbcr,
 	      __u32 &quantization, __u32 &flags, __u32 *bytesperline);
Signature · 1 line
2.17.1
#6 lore raw

Re: [v4l-utils PATCH v2 5/5] v4l2-ctl: Add --stream-pixformat option

Hi Dafna,

Quoted 5 lines · Dafna Hirschfeld

This option sets the capture pixelformat in the capture setup sequence.
If the format is not supported decoding will stop. If the option is not given then the default is to set the first supported format.

I'm not convinced about this patch. Is there any reason why you can't reuse the -v option for this?

What I would expect to happen is this:

If a decoder is detected, then -v doesn't set the current capture format upfront (as happens now), instead it is done when the decoder sends the SOURCE_CHANGE event. Otherwise it works the same: it takes the current format and updates the user-specified fields.

That avoids having to add a new option (we have way too many already).

Regards,

Hans

Quoted 178 lines
---
 utils/v4l2-ctl/v4l2-ctl-streaming.cpp | 37 +++++++++++++++++++++++++
 utils/v4l2-ctl/v4l2-ctl.cpp           | 39 ++++++++++++++++++---------
 utils/v4l2-ctl/v4l2-ctl.h             |  2 ++
 3 files changed, 65 insertions(+), 13 deletions(-)
utils/v4l2-ctl/v4l2-ctl-streaming.cpp +37 -0
index 8d034b85..3e0a449c 100644
@@ -78,6 +78,7 @@ static unsigned int composed_width;
 static unsigned int composed_height;
 static bool support_cap_compose;
 static bool support_out_crop;
+static unsigned int cap_pixelformat;
 static bool in_source_change_event;
 
 #define TS_WINDOW 241
@@ -272,6 +273,10 @@ void streaming_usage(void)
 	       "  --stream-from <file>\n"
 	       "                     stream from this file. The default is to generate a pattern.\n"
 	       "                     If <file> is '-', then the data is read from stdin.\n"
+	       "  --stream-pixformat <pixformat>\n"
+	       "                     set the video pixelformat."
+	       "                     <pixelformat> is either the format index as reported by\n"
+	       "                     --list-formats-out, or the fourcc value as a string.\n"
 	       "  --stream-from-hdr <file> stream from this file. Same as --stream-from, but each\n"
 	       "                     frame is prefixed by a header. Use for compressed data.\n"
 	       "  --stream-from-host <hostname[:port]>\n"
@@ -606,8 +611,16 @@ void streaming_cmd(int ch, char *optarg)
 {
 	unsigned i;
 	int speed;
+	int r;
 
 	switch (ch) {
+	case OptStreamPixformat:
+		r = parse_pixelfmt(optarg, cap_pixelformat);
+		if (r) {
+			streaming_usage();
+			exit(1);
+		}
+		break;
 	case OptStreamCount:
 		stream_count = strtoul(optarg, 0L, 0);
 		break;
@@ -1853,6 +1866,9 @@ enum stream_type {
 
 static int capture_setup(cv4l_fd &fd, cv4l_queue &in)
 {
+	v4l2_fmtdesc fmt_desc;
+	cv4l_fmt fmt;
+
 	if (fd.streamoff(in.g_type())) {
 		fprintf(stderr, "%s: fd.streamoff error\n", __func__);
 		return -1;
@@ -1865,6 +1881,27 @@ static int capture_setup(cv4l_fd &fd, cv4l_queue &in)
 		return -1;
 	}
 
+	if (cap_pixelformat) {
+		if (fd.enum_fmt(fmt_desc, true, 0, in.g_type())) {
+			fprintf(stderr, "%s: fd.enum_fmt error\n", __func__);
+			return -1;
+		}
+
+		do {
+			if (cap_pixelformat == fmt_desc.pixelformat)
+				break;
+		} while (!fd.enum_fmt(fmt_desc));
+
+		if (cap_pixelformat != fmt_desc.pixelformat) {
+			fprintf(stderr, "%s: format from user not supported\n", __func__);
+			return -1;
+		}
+
+		fd.g_fmt(fmt, in.g_type());
+		fmt.s_pixelformat(cap_pixelformat);
+		fd.s_fmt(fmt, in.g_type());
+	}
+
 	if (in.reqbufs(&fd, reqbufs_count_cap)) {
 		fprintf(stderr, "%s: in.reqbufs %u error\n", __func__,
 			reqbufs_count_cap);
utils/v4l2-ctl/v4l2-ctl.cpp +26 -13
index 1783979d..2cbf519e 100644
@@ -238,6 +238,7 @@ static struct option long_options[] = {
 	{"list-buffers-sdr", no_argument, 0, OptListBuffersSdr},
 	{"list-buffers-sdr-out", no_argument, 0, OptListBuffersSdrOut},
 	{"list-buffers-meta", no_argument, 0, OptListBuffersMeta},
+	{"stream-pixformat", required_argument, 0, OptStreamPixformat},
 	{"stream-count", required_argument, 0, OptStreamCount},
 	{"stream-skip", required_argument, 0, OptStreamSkip},
 	{"stream-loop", no_argument, 0, OptStreamLoop},
@@ -722,6 +723,30 @@ __u32 parse_quantization(const char *s)
 	return V4L2_QUANTIZATION_DEFAULT;
 }
 
+int parse_pixelfmt(char *value,  __u32 &pixelformat)
+{
+	int fmts = 0;
+	bool be_pixfmt;
+
+	if(!value)
+		return -EINVAL;
+
+	be_pixfmt = strlen(value) == 7 && !memcmp(value + 4, "-BE", 3);
+	if (be_pixfmt)
+		value[4] = 0;
+	if (strlen(value) == 4) {
+		pixelformat =
+			v4l2_fourcc(value[0], value[1],
+					value[2], value[3]);
+		if (be_pixfmt)
+			pixelformat |= 1 << 31;
+	} else {
+		pixelformat = strtol(value, 0L, 0);
+	}
+	fmts |= FmtPixelFormat;
+	return 0;
+}
+
 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 	      __u32 &field, __u32 &colorspace, __u32 &xfer_func, __u32 &ycbcr,
 	      __u32 &quantization, __u32 &flags, __u32 *bytesperline)
@@ -729,7 +754,6 @@ int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 	char *value, *subs;
 	int fmts = 0;
 	unsigned bpl_index = 0;
-	bool be_pixfmt;
 
 	field = V4L2_FIELD_ANY;
 	flags = 0;
@@ -760,18 +784,7 @@ int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 			fmts |= FmtHeight;
 			break;
 		case 2:
-			be_pixfmt = strlen(value) == 7 && !memcmp(value + 4, "-BE", 3);
-			if (be_pixfmt)
-				value[4] = 0;
-			if (strlen(value) == 4) {
-				pixelformat =
-					v4l2_fourcc(value[0], value[1],
-							value[2], value[3]);
-				if (be_pixfmt)
-					pixelformat |= 1 << 31;
-			} else {
-				pixelformat = strtol(value, 0L, 0);
-			}
+			parse_pixelfmt(value, pixelformat);
 			fmts |= FmtPixelFormat;
 			break;
 		case 3:
utils/v4l2-ctl/v4l2-ctl.h +2 -0
index 5a52a0a4..8eee5351 100644
@@ -205,6 +205,7 @@ enum Option {
 	OptListBuffersSdr,
 	OptListBuffersSdrOut,
 	OptListBuffersMeta,
+	OptStreamPixformat,
 	OptStreamCount,
 	OptStreamSkip,
 	OptStreamLoop,
@@ -299,6 +300,7 @@ __u32 parse_xfer_func(const char *s);
 __u32 parse_ycbcr(const char *s);
 __u32 parse_hsv(const char *s);
 __u32 parse_quantization(const char *s);
+int parse_pixelfmt(char *value,  __u32 &pixelformat);
 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 	      __u32 &field, __u32 &colorspace, __u32 &xfer, __u32 &ycbcr,
 	      __u32 &quantization, __u32 &flags, __u32 *bytesperline);