v4l2-ctl: add support for custom bytesperline values.
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 10 Mar 2014 23:53:30 +0000 (00:53 +0100)
committerHans Verkuil <hans.verkuil@cisco.com>
Mon, 10 Mar 2014 23:56:59 +0000 (00:56 +0100)
The V4L2 API allows application to select a bytesperline value that's larger
than what the driver gives you, effectively padding each line.

Add support to v4l2-ctl to set custom bytesperline values when trying/setting
new formats.

This also fixes a bug where setting multiplanar formats failed: in the *_cmd
function the is_multiplanar global variable isn't set yet because the device
hasn't been opened. So it always assumed a single planar format.

The fixed code is actually cleaner than what I had before.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
utils/v4l2-ctl/v4l2-ctl-vidcap.cpp
utils/v4l2-ctl/v4l2-ctl-vidout.cpp
utils/v4l2-ctl/v4l2-ctl.cpp
utils/v4l2-ctl/v4l2-ctl.h

index c979b22..01b386c 100644 (file)
 
 #include "v4l2-ctl.h"
 
-static struct v4l2_format vfmt_cap;    /* set_format/get_format for video */
 static struct v4l2_frmsizeenum frmsize; /* list frame sizes */
 static struct v4l2_frmivalenum frmival; /* list frame intervals */
 static unsigned set_fmts;
+static __u32 width, height, pixfmt, field;
+static __u32 bytesperline[VIDEO_MAX_PLANES];
 
 void vidcap_usage(void)
 {
@@ -44,10 +45,11 @@ void vidcap_usage(void)
               "  -V, --get-fmt-video\n"
               "                     query the video capture format [VIDIOC_G_FMT]\n"
               "  -v, --set-fmt-video\n"
-              "  --try-fmt-video=width=<w>,height=<h>,pixelformat=<pf>,field=<f>\n"
+              "  --try-fmt-video=width=<w>,height=<h>,pixelformat=<pf>,field=<f>,bytesperline=<bpl>\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"
               "                     <f> can be one of:\n"
               "                     any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
               "                     alternate, interlaced_tb, interlaced_bt\n"
@@ -185,30 +187,17 @@ static void print_video_fields(int fd)
 
 void vidcap_cmd(int ch, char *optarg)
 {
-       __u32 width, height, pixfmt, field, colorspace;
+       __u32 colorspace;
        char *value, *subs;
 
        switch (ch) {
        case OptSetVideoFormat:
        case OptTryVideoFormat:
-               set_fmts = parse_fmt(optarg, width, height, pixfmt, field, colorspace);
+               set_fmts = parse_fmt(optarg, width, height, pixfmt, field, colorspace, bytesperline);
                if (!set_fmts || (set_fmts & FmtColorspace)) {
                        vidcap_usage();
                        exit(1);
                }
-               if (is_multiplanar) {
-                       vfmt_cap.fmt.pix_mp.width = width;
-                       vfmt_cap.fmt.pix_mp.height = height;
-                       vfmt_cap.fmt.pix_mp.pixelformat = pixfmt;
-                       vfmt_cap.fmt.pix_mp.field = field;
-                       vfmt_cap.fmt.pix_mp.colorspace = colorspace;
-               } else {
-                       vfmt_cap.fmt.pix.width = width;
-                       vfmt_cap.fmt.pix.height = height;
-                       vfmt_cap.fmt.pix.pixelformat = pixfmt;
-                       vfmt_cap.fmt.pix.field = field;
-                       vfmt_cap.fmt.pix.colorspace = colorspace;
-               }
                break;
        case OptListFrameSizes:
                if (strlen(optarg) == 4)
@@ -259,14 +248,15 @@ void vidcap_set(int fd)
                struct v4l2_format vfmt;
 
                vfmt.type = vidcap_buftype;
+
                if (doioctl(fd, VIDIOC_G_FMT, &vfmt) == 0) {
                        if (is_multiplanar) {
                                if (set_fmts & FmtWidth)
-                                       vfmt.fmt.pix_mp.width = vfmt_cap.fmt.pix_mp.width;
+                                       vfmt.fmt.pix_mp.width = width;
                                if (set_fmts & FmtHeight)
-                                       vfmt.fmt.pix_mp.height = vfmt_cap.fmt.pix_mp.height;
+                                       vfmt.fmt.pix_mp.height = height;
                                if (set_fmts & FmtPixelFormat) {
-                                       vfmt.fmt.pix_mp.pixelformat = vfmt_cap.fmt.pix_mp.pixelformat;
+                                       vfmt.fmt.pix_mp.pixelformat = pixfmt;
                                        if (vfmt.fmt.pix_mp.pixelformat < 256) {
                                                vfmt.fmt.pix_mp.pixelformat =
                                                        find_pixel_format(fd, vfmt.fmt.pix_mp.pixelformat,
@@ -274,19 +264,25 @@ void vidcap_set(int fd)
                                        }
                                }
                                if (set_fmts & FmtField)
-                                       vfmt.fmt.pix_mp.field = vfmt_cap.fmt.pix_mp.field;
-                               /* G_FMT might return bytesperline values > width,
-                                * reset them to 0 to force the driver to update them
-                                * to the closest value for the new width. */
-                               for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
-                                       vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
+                                       vfmt.fmt.pix_mp.field = field;
+                               if (set_fmts & FmtBytesPerLine) {
+                                       for (unsigned i = 0; i < VIDEO_MAX_PLANES; i++)
+                                               vfmt.fmt.pix_mp.plane_fmt[i].bytesperline =
+                                                       bytesperline[i];
+                               } else {
+                                       /* G_FMT might return bytesperline values > width,
+                                        * reset them to 0 to force the driver to update them
+                                        * to the closest value for the new width. */
+                                       for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
+                                               vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
+                               }
                        } else {
                                if (set_fmts & FmtWidth)
-                                       vfmt.fmt.pix.width = vfmt_cap.fmt.pix.width;
+                                       vfmt.fmt.pix.width = width;
                                if (set_fmts & FmtHeight)
-                                       vfmt.fmt.pix.height = vfmt_cap.fmt.pix.height;
+                                       vfmt.fmt.pix.height = height;
                                if (set_fmts & FmtPixelFormat) {
-                                       vfmt.fmt.pix.pixelformat = vfmt_cap.fmt.pix.pixelformat;
+                                       vfmt.fmt.pix.pixelformat = pixfmt;
                                        if (vfmt.fmt.pix.pixelformat < 256) {
                                                vfmt.fmt.pix.pixelformat =
                                                        find_pixel_format(fd, vfmt.fmt.pix.pixelformat,
@@ -294,11 +290,15 @@ void vidcap_set(int fd)
                                        }
                                }
                                if (set_fmts & FmtField)
-                                       vfmt.fmt.pix.field = vfmt_cap.fmt.pix.field;
-                               /* G_FMT might return a bytesperline value > width,
-                                * reset this to 0 to force the driver to update it
-                                * to the closest value for the new width. */
-                               vfmt.fmt.pix.bytesperline = 0;
+                                       vfmt.fmt.pix.field = field;
+                               if (set_fmts & FmtBytesPerLine) {
+                                       vfmt.fmt.pix.bytesperline = bytesperline[0];
+                               } else {
+                                       /* G_FMT might return a bytesperline value > width,
+                                        * reset this to 0 to force the driver to update it
+                                        * to the closest value for the new width. */
+                                       vfmt.fmt.pix.bytesperline = 0;
+                               }
                        }
 
                        if (options[OptSetVideoFormat])
@@ -314,9 +314,11 @@ void vidcap_set(int fd)
 void vidcap_get(int fd)
 {
        if (options[OptGetVideoFormat]) {
-               vfmt_cap.type = vidcap_buftype;
-               if (doioctl(fd, VIDIOC_G_FMT, &vfmt_cap) == 0)
-                       printfmt(vfmt_cap);
+               struct v4l2_format vfmt;
+
+               vfmt.type = vidcap_buftype;
+               if (doioctl(fd, VIDIOC_G_FMT, &vfmt) == 0)
+                       printfmt(vfmt);
        }
 }
 
index 1d99f4a..3bf1254 100644 (file)
@@ -21,8 +21,9 @@
 
 #include "v4l2-ctl.h"
 
-static struct v4l2_format vfmt_out;    /* set_format/get_format for video */
 static unsigned set_fmts_out;
+static __u32 width, height, pixfmt, field, colorspace;
+static __u32 bytesperline[VIDEO_MAX_PLANES];
 
 void vidout_usage(void)
 {
@@ -32,10 +33,11 @@ void vidout_usage(void)
               "  --get-fmt-video-out\n"
               "                     query the video output format [VIDIOC_G_FMT]\n"
               "  --set-fmt-video-out\n"
-              "  --try-fmt-video-out=width=<w>,height=<h>,pixelformat=<pf>,field=<f>,colorspace=<c>\n"
+              "  --try-fmt-video-out=width=<w>,height=<h>,pixelformat=<pf>,field=<f>,colorspace=<c>,bytesperline=<bpl>\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"
+              "                     The bytesperline option can be used multiple times, once for each plane.\n"
               "                     <f> can be one of:\n"
               "                     any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
               "                     alternate, interlaced_tb, interlaced_bt\n"
@@ -75,29 +77,14 @@ static void print_video_out_fields(int fd)
 
 void vidout_cmd(int ch, char *optarg)
 {
-       __u32 width, height, pixfmt, field, colorspace;
-
        switch (ch) {
        case OptSetVideoOutFormat:
        case OptTryVideoOutFormat:
-               set_fmts_out = parse_fmt(optarg, width, height, pixfmt, field, colorspace);
+               set_fmts_out = parse_fmt(optarg, width, height, pixfmt, field, colorspace, bytesperline);
                if (!set_fmts_out) {
                        vidcap_usage();
                        exit(1);
                }
-               if (is_multiplanar) {
-                       vfmt_out.fmt.pix_mp.width = width;
-                       vfmt_out.fmt.pix_mp.height = height;
-                       vfmt_out.fmt.pix_mp.pixelformat = pixfmt;
-                       vfmt_out.fmt.pix_mp.field = field;
-                       vfmt_out.fmt.pix_mp.colorspace = colorspace;
-               } else {
-                       vfmt_out.fmt.pix.width = width;
-                       vfmt_out.fmt.pix.height = height;
-                       vfmt_out.fmt.pix.pixelformat = pixfmt;
-                       vfmt_out.fmt.pix.field = field;
-                       vfmt_out.fmt.pix.colorspace = colorspace;
-               }
                break;
        }
 }
@@ -113,11 +100,11 @@ void vidout_set(int fd)
                if (doioctl(fd, VIDIOC_G_FMT, &vfmt) == 0) {
                        if (is_multiplanar) {
                                if (set_fmts_out & FmtWidth)
-                                       vfmt.fmt.pix_mp.width = vfmt_out.fmt.pix_mp.width;
+                                       vfmt.fmt.pix_mp.width = width;
                                if (set_fmts_out & FmtHeight)
-                                       vfmt.fmt.pix_mp.height = vfmt_out.fmt.pix_mp.height;
+                                       vfmt.fmt.pix_mp.height = height;
                                if (set_fmts_out & FmtPixelFormat) {
-                                       vfmt.fmt.pix_mp.pixelformat = vfmt_out.fmt.pix_mp.pixelformat;
+                                       vfmt.fmt.pix_mp.pixelformat = pixfmt;
                                        if (vfmt.fmt.pix_mp.pixelformat < 256) {
                                                vfmt.fmt.pix_mp.pixelformat =
                                                        find_pixel_format(fd, vfmt.fmt.pix_mp.pixelformat,
@@ -125,21 +112,27 @@ void vidout_set(int fd)
                                        }
                                }
                                if (set_fmts_out & FmtField)
-                                       vfmt.fmt.pix_mp.field = vfmt_out.fmt.pix_mp.field;
+                                       vfmt.fmt.pix_mp.field = field;
                                if (set_fmts_out & FmtColorspace)
-                                       vfmt.fmt.pix_mp.colorspace = vfmt_out.fmt.pix_mp.colorspace;
-                               /* G_FMT might return bytesperline values > width,
-                                * reset them to 0 to force the driver to update them
-                                * to the closest value for the new width. */
-                               for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
-                                       vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
+                                       vfmt.fmt.pix_mp.colorspace = colorspace;
+                               if (set_fmts_out & FmtBytesPerLine) {
+                                       for (unsigned i = 0; i < VIDEO_MAX_PLANES; i++)
+                                               vfmt.fmt.pix_mp.plane_fmt[i].bytesperline =
+                                                       bytesperline[i];
+                               } else {
+                                       /* G_FMT might return bytesperline values > width,
+                                        * reset them to 0 to force the driver to update them
+                                        * to the closest value for the new width. */
+                                       for (unsigned i = 0; i < vfmt.fmt.pix_mp.num_planes; i++)
+                                               vfmt.fmt.pix_mp.plane_fmt[i].bytesperline = 0;
+                               }
                        } else {
                                if (set_fmts_out & FmtWidth)
-                                       vfmt.fmt.pix.width = vfmt_out.fmt.pix.width;
+                                       vfmt.fmt.pix.width = width;
                                if (set_fmts_out & FmtHeight)
-                                       vfmt.fmt.pix.height = vfmt_out.fmt.pix.height;
+                                       vfmt.fmt.pix.height = height;
                                if (set_fmts_out & FmtPixelFormat) {
-                                       vfmt.fmt.pix.pixelformat = vfmt_out.fmt.pix.pixelformat;
+                                       vfmt.fmt.pix.pixelformat = pixfmt;
                                        if (vfmt.fmt.pix.pixelformat < 256) {
                                                vfmt.fmt.pix.pixelformat =
                                                        find_pixel_format(fd, vfmt.fmt.pix.pixelformat,
@@ -147,13 +140,17 @@ void vidout_set(int fd)
                                        }
                                }
                                if (set_fmts_out & FmtField)
-                                       vfmt.fmt.pix.field = vfmt_out.fmt.pix.field;
+                                       vfmt.fmt.pix.field = field;
                                if (set_fmts_out & FmtColorspace)
-                                       vfmt.fmt.pix.colorspace = vfmt_out.fmt.pix.colorspace;
-                               /* G_FMT might return a bytesperline value > width,
-                                * reset this to 0 to force the driver to update it
-                                * to the closest value for the new width. */
-                               vfmt.fmt.pix.bytesperline = 0;
+                                       vfmt.fmt.pix.colorspace = colorspace;
+                               if (set_fmts_out & FmtBytesPerLine) {
+                                       vfmt.fmt.pix.bytesperline = bytesperline[0];
+                               } else {
+                                       /* G_FMT might return a bytesperline value > width,
+                                        * reset this to 0 to force the driver to update it
+                                        * to the closest value for the new width. */
+                                       vfmt.fmt.pix.bytesperline = 0;
+                               }
                        }
 
                        if (options[OptSetVideoOutFormat])
@@ -169,9 +166,11 @@ void vidout_set(int fd)
 void vidout_get(int fd)
 {
        if (options[OptGetVideoOutFormat]) {
-               vfmt_out.type = vidout_buftype;
-               if (doioctl(fd, VIDIOC_G_FMT, &vfmt_out) == 0)
-                       printfmt(vfmt_out);
+               struct v4l2_format vfmt;
+
+               vfmt.type = vidout_buftype;
+               if (doioctl(fd, VIDIOC_G_FMT, &vfmt) == 0)
+                       printfmt(vfmt);
        }
 }
 
index 13944e2..6baae8e 100644 (file)
@@ -696,10 +696,11 @@ static __u32 parse_colorspace(const char *s)
 }
 
 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
-             __u32 &field, __u32 &colorspace)
+             __u32 &field, __u32 &colorspace, __u32 *bytesperline)
 {
        char *value, *subs;
        int fmts = 0;
+       unsigned bpl_index = 0;
 
        field = V4L2_FIELD_ANY;
        subs = optarg;
@@ -710,16 +711,17 @@ int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
                        "pixelformat",
                        "field",
                        "colorspace",
+                       "bytesperline",
                        NULL
                };
 
                switch (parse_subopt(&subs, subopts, &value)) {
                case 0:
-                       width = strtol(value, 0L, 0);
+                       width = strtoul(value, 0L, 0);
                        fmts |= FmtWidth;
                        break;
                case 1:
-                       height = strtol(value, 0L, 0);
+                       height = strtoul(value, 0L, 0);
                        fmts |= FmtHeight;
                        break;
                case 2:
@@ -742,6 +744,15 @@ int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
                        else
                                fprintf(stderr, "unknown colorspace %s\n", value);
                        break;
+               case 5:
+                       bytesperline[bpl_index] = strtoul(value, 0L, 0);
+                       if (bytesperline[bpl_index] > 0xffff) {
+                               fprintf(stderr, "bytesperline can't be more than 65535\n");
+                               bytesperline[bpl_index] = 0;
+                       }
+                       bpl_index++;
+                       fmts |= FmtBytesPerLine;
+                       break;
                default:
                        return 0;
                }
index f9ef10d..1a21335 100644 (file)
@@ -187,6 +187,7 @@ typedef struct {
 #define FmtTop                 (1L<<6)
 #define FmtField               (1L<<7)
 #define FmtColorspace          (1L<<8)
+#define FmtBytesPerLine                (1L<<9)
 
 // v4l2-ctl.cpp
 int doioctl_name(int fd, unsigned long int request, void *parm, const char *name);
@@ -203,7 +204,7 @@ std::string field2s(int val);
 void print_v4lstd(v4l2_std_id std);
 __u32 parse_field(const char *s);
 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
-             __u32 &field, __u32 &colorspace);
+             __u32 &field, __u32 &colorspace, __u32 *bytesperline);
 __u32 find_pixel_format(int fd, unsigned index, bool output, bool mplane);
 void printfmt(const struct v4l2_format &vfmt);
 void print_video_formats(int fd, __u32 type);