diff mbox series

v4l2-ctl: add sizeimage suboption for set-fmt-video options

Message ID 1569085532-17991-1-git-send-email-akinobu.mita@gmail.com (mailing list archive)
State New, archived
Headers show
Series v4l2-ctl: add sizeimage suboption for set-fmt-video options | expand

Commit Message

Akinobu Mita Sept. 21, 2019, 5:05 p.m. UTC
When I tried to run v4l2-ctl streaming tests with the Hantro VPU JPEG
encoder on ROCKPro64, the following command generates empty output file.

v4l2-ctl -d /dev/video1 --stream-from=/dev/urandom --stream-to=out.jpg \
  --set-fmt-video-out=width=640,height=480 \
  --set-fmt-video=width=640,height=480 \
  --stream-mmap=1 --stream-out-mmap=1 --stream-count=1

This is because the sizeimage field for encoded format is too small.

When opening the video device for the Hantro VPU JPEG encoder, the
sizeimage field for encoded format is reset to the maximum size in bytes
required for the minimam frame size (96x32) by hantro_reset_encoded_fmt()
in linux/drivers/staging/media/hantro/hantro_v4l2.c.

Currently v4l2-ctl doesn't touch the sizeimage fields, so when the frame
size is not small, the JPEG encoder cannot get enough buffer size.

This adds sizeimage suboption for set-fmt-video options and the following
command generates correct jpeg image.

v4l2-ctl -d /dev/video1 --stream-from=/dev/urandom --stream-to=out.jpg \
  --set-fmt-video-out=width=640,height=480 \
  --set-fmt-video=width=640,height=480,sizeimage=0 \
  --stream-mmap=1 --stream-out-mmap=1 --stream-count=1

The following comment for vidioc_try_fmt() in
linux/drivers/staging/media/hantro/hantro_v4l2.c explains why a zero
sizeimage is passed.

		/*
		 * For coded formats the application can specify
		 * sizeimage. If the application passes a zero sizeimage,
		 * let's default to the maximum frame size.
		 */

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Cc: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
 utils/v4l2-ctl/v4l2-ctl-vidcap.cpp | 16 +++++++++++++---
 utils/v4l2-ctl/v4l2-ctl-vidout.cpp | 16 +++++++++++++---
 utils/v4l2-ctl/v4l2-ctl.cpp        | 10 +++++++++-
 utils/v4l2-ctl/v4l2-ctl.h          |  4 +++-
 4 files changed, 38 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp b/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
index 15ffbea..3a29251 100644
--- a/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
@@ -21,6 +21,7 @@  static struct v4l2_frmivalenum frmival; /* list frame intervals */
 static unsigned set_fmts;
 static __u32 width, height, pixfmt, field, flags;
 static __u32 bytesperline[VIDEO_MAX_PLANES];
+static __u32 sizeimage[VIDEO_MAX_PLANES];
 
 void vidcap_usage(void)
 {
@@ -42,11 +43,12 @@  void vidcap_usage(void)
 	       "  -v, --set-fmt-video\n"
 	       "  --try-fmt-video width=<w>,height=<h>,pixelformat=<pf>,field=<f>,colorspace=<c>,\n"
 	       "                  xfer=<xf>,ycbcr=<y>,hsv=<hsv>,quantization=<q>,\n"
-	       "                  premul-alpha,bytesperline=<bpl>\n"
+	       "                  premul-alpha,bytesperline=<bpl>,sizeimage=<sz>\n"
 	       "                     set/try the video capture format [VIDIOC_S/TRY_FMT]\n"
 	       "                     pixelformat is either the format index as reported by\n"
 	       "                       --list-formats, or the fourcc value as a string.\n"
-	       "                     The bytesperline option can be used multiple times, once for each plane.\n"
+	       "                     The bytesperline and sizeimage options can be used multiple times,\n"
+	       "                       once for each plane.\n"
 	       "                     premul-alpha sets V4L2_PIX_FMT_FLAG_PREMUL_ALPHA.\n"
 	       "                     <f> can be one of the following field layouts:\n"
 	       "                       any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
@@ -106,7 +108,8 @@  void vidcap_cmd(int ch, char *optarg)
 	case OptSetVideoFormat:
 	case OptTryVideoFormat:
 		set_fmts = parse_fmt(optarg, width, height, pixfmt, field, colorspace,
-				xfer_func, ycbcr, quantization, flags, bytesperline);
+				xfer_func, ycbcr, quantization, flags, bytesperline,
+				sizeimage);
 		if (!set_fmts ||
 		    (set_fmts & (FmtColorspace | FmtYCbCr | FmtQuantization | FmtXferFunc))) {
 			vidcap_usage();
@@ -211,6 +214,11 @@  int vidcap_get_and_update_fmt(cv4l_fd &_fd, struct v4l2_format &vfmt)
 			for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
 				vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
 		}
+		if (set_fmts & FmtSizeImage) {
+			for (unsigned i = 0; i < VIDEO_MAX_PLANES; i++)
+				vfmt.fmt.pix_mp.plane_fmt[i].sizeimage =
+					sizeimage[i];
+		}
 	} else {
 		if (set_fmts & FmtWidth)
 			vfmt.fmt.pix.width = width;
@@ -238,6 +246,8 @@  int vidcap_get_and_update_fmt(cv4l_fd &_fd, struct v4l2_format &vfmt)
 			 */
 			vfmt.fmt.pix.bytesperline = 0;
 		}
+		if (set_fmts & FmtSizeImage)
+			vfmt.fmt.pix.sizeimage = sizeimage[0];
 	}
 
 	if ((set_fmts & FmtPixelFormat) &&
diff --git a/utils/v4l2-ctl/v4l2-ctl-vidout.cpp b/utils/v4l2-ctl/v4l2-ctl-vidout.cpp
index c90bee5..227d624 100644
--- a/utils/v4l2-ctl/v4l2-ctl-vidout.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-vidout.cpp
@@ -19,6 +19,7 @@ 
 static unsigned set_fmts_out;
 static __u32 width, height, pixfmt, field, colorspace, xfer_func, ycbcr, quantization, flags;
 static __u32 bytesperline[VIDEO_MAX_PLANES];
+static __u32 sizeimage[VIDEO_MAX_PLANES];
 
 void vidout_usage(void)
 {
@@ -33,12 +34,13 @@  void vidout_usage(void)
 	       "  -x, --set-fmt-video-out\n"
 	       "  --try-fmt-video-out width=<w>,height=<h>,pixelformat=<pf>,field=<f>,colorspace=<c>,\n"
 	       "                      xfer=<xf>,ycbcr=<y>,hsv=<hsv>,quantization=<q>,\n"
-	       "                      premul-alpha,bytesperline=<bpl>\n"
+	       "                      premul-alpha,bytesperline=<bpl>,sizeimage=<sz>\n"
 	       "                     set/try the video output format [VIDIOC_S/TRY_FMT]\n"
 	       "                     pixelformat is either the format index as reported by\n"
 	       "                       --list-formats-out, or the fourcc value as a string.\n"
 	       "                     premul-alpha sets V4L2_PIX_FMT_FLAG_PREMUL_ALPHA.\n"
-	       "                     The bytesperline option can be used multiple times, once for each plane.\n"
+	       "                     The bytesperline and sizeimage options can be used multiple times,\n"
+	       "                       once for each plane.\n"
 	       "                     <f> can be one of the following field layouts:\n"
 	       "                       any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
 	       "                       alternate, interlaced_tb, interlaced_bt\n"
@@ -93,7 +95,8 @@  void vidout_cmd(int ch, char *optarg)
 	case OptSetVideoOutFormat:
 	case OptTryVideoOutFormat:
 		set_fmts_out = parse_fmt(optarg, width, height, pixfmt, field,
-				colorspace, xfer_func, ycbcr, quantization, flags, bytesperline);
+				colorspace, xfer_func, ycbcr, quantization, flags, bytesperline,
+				sizeimage);
 		if (!set_fmts_out) {
 			vidcap_usage();
 			exit(1);
@@ -150,6 +153,11 @@  void vidout_set(cv4l_fd &_fd)
 					for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
 						vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
 				}
+				if (set_fmts_out & FmtSizeImage) {
+					for (unsigned i = 0; i < VIDEO_MAX_PLANES; i++)
+						vfmt.fmt.pix_mp.plane_fmt[i].sizeimage =
+							sizeimage[i];
+				}
 			} else {
 				if (set_fmts_out & FmtWidth)
 					vfmt.fmt.pix.width = width;
@@ -183,6 +191,8 @@  void vidout_set(cv4l_fd &_fd)
 					 * to the closest value for the new width. */
 					vfmt.fmt.pix.bytesperline = 0;
 				}
+				if (set_fmts_out & FmtSizeImage)
+					vfmt.fmt.pix.sizeimage = sizeimage[0];
 			}
 
 			if ((set_fmts_out & FmtPixelFormat) &&
diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp
index 3a2d082..77e0d36 100644
--- a/utils/v4l2-ctl/v4l2-ctl.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl.cpp
@@ -744,11 +744,13 @@  __u32 parse_quantization(const char *s)
 
 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)
+	      __u32 &quantization, __u32 &flags, __u32 *bytesperline,
+	      __u32 *sizeimage)
 {
 	char *value, *subs;
 	int fmts = 0;
 	unsigned bpl_index = 0;
+	unsigned sizeimage_index = 0;
 	bool be_pixfmt;
 
 	field = V4L2_FIELD_ANY;
@@ -767,6 +769,7 @@  int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 			"premul-alpha",
 			"quantization",
 			"xfer",
+			"sizeimage",
 			NULL
 		};
 
@@ -835,6 +838,11 @@  int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
 			xfer_func = parse_xfer_func(value);
 			fmts |= FmtXferFunc;
 			break;
+		case 11:
+			sizeimage[sizeimage_index] = strtoul(value, 0L, 0);
+			sizeimage_index++;
+			fmts |= FmtSizeImage;
+			break;
 		default:
 			return 0;
 		}
diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h
index 5797d78..46c87b5 100644
--- a/utils/v4l2-ctl/v4l2-ctl.h
+++ b/utils/v4l2-ctl/v4l2-ctl.h
@@ -296,6 +296,7 @@  typedef struct {
 #define FmtFlags		(1L<<11)
 #define FmtBytesPerLine		(1L<<12)
 #define FmtXferFunc		(1L<<13)
+#define FmtSizeImage		(1L<<14)
 
 // v4l2-ctl.cpp
 int doioctl_name(int fd, unsigned long int request, void *parm, const char *name);
@@ -309,7 +310,8 @@  __u32 parse_hsv(const char *s);
 __u32 parse_quantization(const char *s);
 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);
+	      __u32 &quantization, __u32 &flags, __u32 *bytesperline,
+	      __u32 *sizeimage);
 int parse_selection_target(const char *s, unsigned int &target);
 int parse_selection_flags(const char *s);
 void print_selection(const struct v4l2_selection &sel);