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@xxxxxxxxx> Cc: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx> Signed-off-by: Akinobu Mita <akinobu.mita@xxxxxxxxx> --- 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 --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); -- 2.7.4