[{"id":900,"web_url":"https://patchwork.libcamera.org/comment/900/","msgid":"<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>","date":"2019-02-26T23:19:40","subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn 26/02/2019 16:26, Jacopo Mondi wrote:\n> Implement enumFormat() methods to enumerate the available image\n> resolutions on the subdevice.\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  src/libcamera/include/v4l2_subdevice.h |   9 ++\n>  src/libcamera/v4l2_subdevice.cpp       | 118 +++++++++++++++++++++++++\n>  2 files changed, 127 insertions(+)\n> \n> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h\n> index eac699a06109..6b21308d2087 100644\n> --- a/src/libcamera/include/v4l2_subdevice.h\n> +++ b/src/libcamera/include/v4l2_subdevice.h\n> @@ -7,7 +7,9 @@\n>  #ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__\n>  #define __LIBCAMERA_V4L2_SUBDEVICE_H__\n>  \n> +#include <map>\n>  #include <string>\n> +#include <vector>\n>  \n>  #include \"media_object.h\"\n>  \n> @@ -38,15 +40,22 @@ public:\n>  \tint setCrop(unsigned int pad, Rectangle *rect);\n>  \tint setCompose(unsigned int pad, Rectangle *rect);\n>  \n> +\tstd::vector<V4L2SubdeviceFormat> &formats(unsigned int pad);\n>  \tint getFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n>  \tint setFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n>  \n>  private:\n> +\tint listPadSizes(unsigned int pad, unsigned int mbus_code,\n> +\t\t\t std::vector<V4L2SubdeviceFormat> *formats);\n> +\tstd::vector<V4L2SubdeviceFormat> listPadFormats(unsigned int pad);\n\n\nThe word 'list' seems a bit redundant in 'listPadSizes()' and\n'listPadFormats()' ... and seems a bit hungarian notation to me?\n\nOther than that, I trust that the tests that follow make sure the code\nis doing something sane :)\n\n\nI can't see anything jump out at me yet.\n\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\n\n\n> +\n>  \tint setSelection(unsigned int pad, unsigned int target,\n>  \t\t\t Rectangle *rect);\n>  \n>  \tconst MediaEntity *entity_;\n>  \tint fd_;\n> +\n> +\tstd::map<unsigned int, std::vector<V4L2SubdeviceFormat>> formats_;\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> index 56ecf3851cb0..f81a521f9e2a 100644\n> --- a/src/libcamera/v4l2_subdevice.cpp\n> +++ b/src/libcamera/v4l2_subdevice.cpp\n> @@ -5,6 +5,10 @@\n>   * v4l2_subdevice.cpp - V4L2 Subdevice\n>   */\n>  \n> +#include <map>\n> +#include <string>\n> +#include <vector>\n> +\n>  #include <fcntl.h>\n>  #include <string.h>\n>  #include <sys/ioctl.h>\n> @@ -116,6 +120,9 @@ int V4L2Subdevice::open()\n>  \t}\n>  \tfd_ = ret;\n>  \n> +\tfor (MediaPad *pad : entity_->pads())\n> +\t\tformats_[pad->index()] = listPadFormats(pad->index());\n> +\n>  \treturn 0;\n>  }\n>  \n> @@ -178,6 +185,25 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)\n>  \treturn setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);\n>  }\n>  \n> +/**\n> + * \\brief List the sub-device image resolutions and formats on \\a pad\n> + * \\param[in] pad The 0-indexed pad number to enumerate formats on\n> + *\n> + * \\return A vector of image formats, or an empty vector if the pad does not\n> + * exist\n> + */\n> +std::vector<V4L2SubdeviceFormat> &V4L2Subdevice::formats(unsigned int pad)\n> +{\n> +\t/*\n> +\t * If pad does not exist, return an empty vector at position\n> +\t * pads().size()\n> +\t */\n> +\tif (pad > entity_->pads().size())\n> +\t\tpad = entity_->pads().size();\n> +\n> +\treturn formats_[pad];\n> +}\n> +\n>  /**\n>   * \\brief Retrieve the image format set on one of the V4L2 subdevice pads\n>   * \\param[in] pad The 0-indexed pad number the format is to be retrieved from\n> @@ -242,6 +268,98 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n>  \treturn 0;\n>  }\n>  \n> +int V4L2Subdevice::listPadSizes(unsigned int pad, unsigned int mbus_code,\n> +\t\t\t\tstd::vector<V4L2SubdeviceFormat> *formats)\n> +{\n> +\tstruct v4l2_subdev_frame_size_enum sizeEnum = {};\n> +\tint ret;\n> +\n> +\tsizeEnum.index = 0;\n> +\tsizeEnum.pad = pad;\n> +\tsizeEnum.code = mbus_code;\n> +\tsizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> +\n> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum))) {\n> +\t\tV4L2SubdeviceFormat minFormat = {\n> +\t\t\t.mbus_code = mbus_code,\n> +\t\t\t.width = sizeEnum.min_width,\n> +\t\t\t.height = sizeEnum.min_height,\n> +\t\t};\n> +\t\tformats->push_back(minFormat);\n> +\n> +\t\t/*\n> +\t\t * Most subdevices report discrete frame resolutions, where\n> +\t\t * min and max sizes are identical. For continue frame\n> +\t\t * resolutions, store the min and max sizes interval.\n> +\t\t */\n> +\t\tif (sizeEnum.min_width == sizeEnum.max_width &&\n> +\t\t    sizeEnum.min_height == sizeEnum.max_height) {\n> +\t\t\tsizeEnum.index++;\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tV4L2SubdeviceFormat maxFormat = {\n> +\t\t\t.mbus_code = mbus_code,\n> +\t\t\t.width = sizeEnum.max_width,\n> +\t\t\t.height = sizeEnum.max_height,\n> +\t\t};\n> +\t\tformats->push_back(maxFormat);\n> +\n> +\t\tsizeEnum.index++;\n> +\t}\n> +\n> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> +\t\tLOG(V4L2Subdev, Error)\n> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> +\t\t\t<< \" of \" << deviceName() << \": \"\n> +\t\t\t<< strerror(errno);\n> +\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +std::vector<V4L2SubdeviceFormat> V4L2Subdevice::listPadFormats(unsigned int pad)\n> +{\n> +\tstruct v4l2_subdev_mbus_code_enum mbusEnum = {};\n> +\tstd::vector<V4L2SubdeviceFormat> formats = {};\n> +\tint ret;\n> +\n> +\tmbusEnum.pad = pad;\n> +\tmbusEnum.index = 0;\n> +\tmbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> +\n> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum))) {\n> +\t\tret = listPadSizes(pad, mbusEnum.code, &formats);\n> +\t\tif (ret)\n> +\t\t\treturn formats;\n> +\n> +\t\tmbusEnum.index++;\n> +\t}\n> +\n> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> +\t\tLOG(V4L2Subdev, Error)\n> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> +\t\t\t<< \" of \" << deviceName() << \": \" << strerror(-ret);\n> +\t\treturn formats;\n> +\t}\n> +\n> +\tif (mbusEnum.index == 0 && ret && errno == EINVAL) {\n> +\t\t/*\n> +\t\t * The subdevice might not support ENUM_MBUS_CODE but\n> +\t\t * might support ENUM_FRAME_SIZES.\n> +\t\t */\n> +\t\tstruct V4L2SubdeviceFormat subdevFormat;\n> +\t\tret = getFormat(pad, &subdevFormat);\n> +\t\tif (ret)\n> +\t\t\treturn formats;\n> +\n> +\t\tlistPadSizes(pad, subdevFormat.mbus_code, &formats);\n> +\t}\n> +\n> +\treturn formats;\n> +}\n> +\n>  int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,\n>  \t\t\t\tRectangle *rect)\n>  {\n>","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id E3BA2610B2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Feb 2019 00:19:43 +0100 (CET)","from [192.168.0.21]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1FA4F67;\n\tWed, 27 Feb 2019 00:19:43 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1551223183;\n\tbh=047j9jZhSnZdpcM8Ckl5Xx6fdXF/IKQSit90EO46/eM=;\n\th=Reply-To:Subject:To:References:From:Date:In-Reply-To:From;\n\tb=Usj5Wny+PjvxGNnXAcK8XhXiQ/o+UMBg6sDKFKq5G7PIIzTCw0KyQrjkWh2jKiFIp\n\tpTZna4G6VCjFLLjhc8D+ukZeHW7VdChsHqcYO5/FXVmDqg7QOf8qLeC8pkkdOVikIE\n\tzKHSsECeF1R4moiMOxiOypCXwigI1IchsJh3Ao2o=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Jacopo Mondi <jacopo@jmondi.org>, libcamera-devel@lists.libcamera.org","References":"<20190226162641.12116-1-jacopo@jmondi.org>\n\t<20190226162641.12116-3-jacopo@jmondi.org>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\t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\n\tsbsRB8KNNvVXBOVNwko86rQqF9drZuw=","Organization":"Ideas on Board","Message-ID":"<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>","Date":"Tue, 26 Feb 2019 23:19:40 +0000","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.4.0","MIME-Version":"1.0","In-Reply-To":"<20190226162641.12116-3-jacopo@jmondi.org>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 26 Feb 2019 23:19:44 -0000"}},{"id":909,"web_url":"https://patchwork.libcamera.org/comment/909/","msgid":"<20190227081804.3ey5berzsd57534n@uno.localdomain>","date":"2019-02-27T08:18:04","subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Kieran,\n\nOn Tue, Feb 26, 2019 at 11:19:40PM +0000, Kieran Bingham wrote:\n> Hi Jacopo,\n>\n> On 26/02/2019 16:26, Jacopo Mondi wrote:\n> > Implement enumFormat() methods to enumerate the available image\n> > resolutions on the subdevice.\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > ---\n> >  src/libcamera/include/v4l2_subdevice.h |   9 ++\n> >  src/libcamera/v4l2_subdevice.cpp       | 118 +++++++++++++++++++++++++\n> >  2 files changed, 127 insertions(+)\n> >\n> > diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h\n> > index eac699a06109..6b21308d2087 100644\n> > --- a/src/libcamera/include/v4l2_subdevice.h\n> > +++ b/src/libcamera/include/v4l2_subdevice.h\n> > @@ -7,7 +7,9 @@\n> >  #ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__\n> >  #define __LIBCAMERA_V4L2_SUBDEVICE_H__\n> >\n> > +#include <map>\n> >  #include <string>\n> > +#include <vector>\n> >\n> >  #include \"media_object.h\"\n> >\n> > @@ -38,15 +40,22 @@ public:\n> >  \tint setCrop(unsigned int pad, Rectangle *rect);\n> >  \tint setCompose(unsigned int pad, Rectangle *rect);\n> >\n> > +\tstd::vector<V4L2SubdeviceFormat> &formats(unsigned int pad);\n> >  \tint getFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> >  \tint setFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> >\n> >  private:\n> > +\tint listPadSizes(unsigned int pad, unsigned int mbus_code,\n> > +\t\t\t std::vector<V4L2SubdeviceFormat> *formats);\n> > +\tstd::vector<V4L2SubdeviceFormat> listPadFormats(unsigned int pad);\n>\n>\n> The word 'list' seems a bit redundant in 'listPadSizes()' and\n> 'listPadFormats()' ... and seems a bit hungarian notation to me?\n>\n\nI interpreted \"list\" as a verb, so the function name reads like \"list\nall formats on a pad\". Is it weird to you?\n\n> Other than that, I trust that the tests that follow make sure the code\n> is doing something sane :)\n>\n>\n> I can't see anything jump out at me yet.\n>\n>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nThanks\n  j\n\n>\n>\n>\n> > +\n> >  \tint setSelection(unsigned int pad, unsigned int target,\n> >  \t\t\t Rectangle *rect);\n> >\n> >  \tconst MediaEntity *entity_;\n> >  \tint fd_;\n> > +\n> > +\tstd::map<unsigned int, std::vector<V4L2SubdeviceFormat>> formats_;\n> >  };\n> >\n> >  } /* namespace libcamera */\n> > diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> > index 56ecf3851cb0..f81a521f9e2a 100644\n> > --- a/src/libcamera/v4l2_subdevice.cpp\n> > +++ b/src/libcamera/v4l2_subdevice.cpp\n> > @@ -5,6 +5,10 @@\n> >   * v4l2_subdevice.cpp - V4L2 Subdevice\n> >   */\n> >\n> > +#include <map>\n> > +#include <string>\n> > +#include <vector>\n> > +\n> >  #include <fcntl.h>\n> >  #include <string.h>\n> >  #include <sys/ioctl.h>\n> > @@ -116,6 +120,9 @@ int V4L2Subdevice::open()\n> >  \t}\n> >  \tfd_ = ret;\n> >\n> > +\tfor (MediaPad *pad : entity_->pads())\n> > +\t\tformats_[pad->index()] = listPadFormats(pad->index());\n> > +\n> >  \treturn 0;\n> >  }\n> >\n> > @@ -178,6 +185,25 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)\n> >  \treturn setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);\n> >  }\n> >\n> > +/**\n> > + * \\brief List the sub-device image resolutions and formats on \\a pad\n> > + * \\param[in] pad The 0-indexed pad number to enumerate formats on\n> > + *\n> > + * \\return A vector of image formats, or an empty vector if the pad does not\n> > + * exist\n> > + */\n> > +std::vector<V4L2SubdeviceFormat> &V4L2Subdevice::formats(unsigned int pad)\n> > +{\n> > +\t/*\n> > +\t * If pad does not exist, return an empty vector at position\n> > +\t * pads().size()\n> > +\t */\n> > +\tif (pad > entity_->pads().size())\n> > +\t\tpad = entity_->pads().size();\n> > +\n> > +\treturn formats_[pad];\n> > +}\n> > +\n> >  /**\n> >   * \\brief Retrieve the image format set on one of the V4L2 subdevice pads\n> >   * \\param[in] pad The 0-indexed pad number the format is to be retrieved from\n> > @@ -242,6 +268,98 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n> >  \treturn 0;\n> >  }\n> >\n> > +int V4L2Subdevice::listPadSizes(unsigned int pad, unsigned int mbus_code,\n> > +\t\t\t\tstd::vector<V4L2SubdeviceFormat> *formats)\n> > +{\n> > +\tstruct v4l2_subdev_frame_size_enum sizeEnum = {};\n> > +\tint ret;\n> > +\n> > +\tsizeEnum.index = 0;\n> > +\tsizeEnum.pad = pad;\n> > +\tsizeEnum.code = mbus_code;\n> > +\tsizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> > +\n> > +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum))) {\n> > +\t\tV4L2SubdeviceFormat minFormat = {\n> > +\t\t\t.mbus_code = mbus_code,\n> > +\t\t\t.width = sizeEnum.min_width,\n> > +\t\t\t.height = sizeEnum.min_height,\n> > +\t\t};\n> > +\t\tformats->push_back(minFormat);\n> > +\n> > +\t\t/*\n> > +\t\t * Most subdevices report discrete frame resolutions, where\n> > +\t\t * min and max sizes are identical. For continue frame\n> > +\t\t * resolutions, store the min and max sizes interval.\n> > +\t\t */\n> > +\t\tif (sizeEnum.min_width == sizeEnum.max_width &&\n> > +\t\t    sizeEnum.min_height == sizeEnum.max_height) {\n> > +\t\t\tsizeEnum.index++;\n> > +\t\t\tcontinue;\n> > +\t\t}\n> > +\n> > +\t\tV4L2SubdeviceFormat maxFormat = {\n> > +\t\t\t.mbus_code = mbus_code,\n> > +\t\t\t.width = sizeEnum.max_width,\n> > +\t\t\t.height = sizeEnum.max_height,\n> > +\t\t};\n> > +\t\tformats->push_back(maxFormat);\n> > +\n> > +\t\tsizeEnum.index++;\n> > +\t}\n> > +\n> > +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> > +\t\tLOG(V4L2Subdev, Error)\n> > +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> > +\t\t\t<< \" of \" << deviceName() << \": \"\n> > +\t\t\t<< strerror(errno);\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +std::vector<V4L2SubdeviceFormat> V4L2Subdevice::listPadFormats(unsigned int pad)\n> > +{\n> > +\tstruct v4l2_subdev_mbus_code_enum mbusEnum = {};\n> > +\tstd::vector<V4L2SubdeviceFormat> formats = {};\n> > +\tint ret;\n> > +\n> > +\tmbusEnum.pad = pad;\n> > +\tmbusEnum.index = 0;\n> > +\tmbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> > +\n> > +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum))) {\n> > +\t\tret = listPadSizes(pad, mbusEnum.code, &formats);\n> > +\t\tif (ret)\n> > +\t\t\treturn formats;\n> > +\n> > +\t\tmbusEnum.index++;\n> > +\t}\n> > +\n> > +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> > +\t\tLOG(V4L2Subdev, Error)\n> > +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> > +\t\t\t<< \" of \" << deviceName() << \": \" << strerror(-ret);\n> > +\t\treturn formats;\n> > +\t}\n> > +\n> > +\tif (mbusEnum.index == 0 && ret && errno == EINVAL) {\n> > +\t\t/*\n> > +\t\t * The subdevice might not support ENUM_MBUS_CODE but\n> > +\t\t * might support ENUM_FRAME_SIZES.\n> > +\t\t */\n> > +\t\tstruct V4L2SubdeviceFormat subdevFormat;\n> > +\t\tret = getFormat(pad, &subdevFormat);\n> > +\t\tif (ret)\n> > +\t\t\treturn formats;\n> > +\n> > +\t\tlistPadSizes(pad, subdevFormat.mbus_code, &formats);\n> > +\t}\n> > +\n> > +\treturn formats;\n> > +}\n> > +\n> >  int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,\n> >  \t\t\t\tRectangle *rect)\n> >  {\n> >\n>\n> --\n> Regards\n> --\n> Kieran","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay12.mail.gandi.net (relay12.mail.gandi.net\n\t[217.70.178.232])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1AAF3601E2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Feb 2019 09:17:35 +0100 (CET)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay12.mail.gandi.net (Postfix) with ESMTPSA id 89ABD20000C;\n\tWed, 27 Feb 2019 08:17:34 +0000 (UTC)"],"Date":"Wed, 27 Feb 2019 09:18:04 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190227081804.3ey5berzsd57534n@uno.localdomain>","References":"<20190226162641.12116-1-jacopo@jmondi.org>\n\t<20190226162641.12116-3-jacopo@jmondi.org>\n\t<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"onsvwvz5a72egxbl\"","Content-Disposition":"inline","In-Reply-To":"<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 27 Feb 2019 08:17:35 -0000"}},{"id":929,"web_url":"https://patchwork.libcamera.org/comment/929/","msgid":"<20190227175120.GL4813@pendragon.ideasonboard.com>","date":"2019-02-27T17:51:20","subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Wed, Feb 27, 2019 at 09:18:04AM +0100, Jacopo Mondi wrote:\n> On Tue, Feb 26, 2019 at 11:19:40PM +0000, Kieran Bingham wrote:\n> > On 26/02/2019 16:26, Jacopo Mondi wrote:\n> >> Implement enumFormat() methods to enumerate the available image\n> >> resolutions on the subdevice.\n> >>\n> >> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> >> ---\n> >>  src/libcamera/include/v4l2_subdevice.h |   9 ++\n> >>  src/libcamera/v4l2_subdevice.cpp       | 118 +++++++++++++++++++++++++\n> >>  2 files changed, 127 insertions(+)\n> >>\n> >> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h\n> >> index eac699a06109..6b21308d2087 100644\n> >> --- a/src/libcamera/include/v4l2_subdevice.h\n> >> +++ b/src/libcamera/include/v4l2_subdevice.h\n> >> @@ -7,7 +7,9 @@\n> >>  #ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__\n> >>  #define __LIBCAMERA_V4L2_SUBDEVICE_H__\n> >>\n> >> +#include <map>\n> >>  #include <string>\n> >> +#include <vector>\n> >>\n> >>  #include \"media_object.h\"\n> >>\n> >> @@ -38,15 +40,22 @@ public:\n> >>  \tint setCrop(unsigned int pad, Rectangle *rect);\n> >>  \tint setCompose(unsigned int pad, Rectangle *rect);\n> >>\n> >> +\tstd::vector<V4L2SubdeviceFormat> &formats(unsigned int pad);\n\nShouldn't you return a const reference ? And make this function const ?\n\n> >>  \tint getFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> >>  \tint setFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> >>\n> >>  private:\n> >> +\tint listPadSizes(unsigned int pad, unsigned int mbus_code,\n> >> +\t\t\t std::vector<V4L2SubdeviceFormat> *formats);\n> >> +\tstd::vector<V4L2SubdeviceFormat> listPadFormats(unsigned int pad);\n> >\n> > The word 'list' seems a bit redundant in 'listPadSizes()' and\n> > 'listPadFormats()' ... and seems a bit hungarian notation to me?\n> \n> I interpreted \"list\" as a verb, so the function name reads like \"list\n> all formats on a pad\". Is it weird to you?\n\nHow about s/list/enumerate/ to remove all ambiguity ?\n\n> > Other than that, I trust that the tests that follow make sure the code\n> > is doing something sane :)\n> >\n> > I can't see anything jump out at me yet.\n> >\n> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> >\n> >> +\n> >>  \tint setSelection(unsigned int pad, unsigned int target,\n> >>  \t\t\t Rectangle *rect);\n> >>\n> >>  \tconst MediaEntity *entity_;\n> >>  \tint fd_;\n> >> +\n> >> +\tstd::map<unsigned int, std::vector<V4L2SubdeviceFormat>> formats_;\n> >>  };\n> >>\n> >>  } /* namespace libcamera */\n> >> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> >> index 56ecf3851cb0..f81a521f9e2a 100644\n> >> --- a/src/libcamera/v4l2_subdevice.cpp\n> >> +++ b/src/libcamera/v4l2_subdevice.cpp\n> >> @@ -5,6 +5,10 @@\n> >>   * v4l2_subdevice.cpp - V4L2 Subdevice\n> >>   */\n> >>\n> >> +#include <map>\n> >> +#include <string>\n> >> +#include <vector>\n> >> +\n\nNot strictly needed as the header includes them.\n\n> >>  #include <fcntl.h>\n> >>  #include <string.h>\n> >>  #include <sys/ioctl.h>\n> >> @@ -116,6 +120,9 @@ int V4L2Subdevice::open()\n> >>  \t}\n> >>  \tfd_ = ret;\n> >>\n> >> +\tfor (MediaPad *pad : entity_->pads())\n> >> +\t\tformats_[pad->index()] = listPadFormats(pad->index());\n> >> +\n\nShould you do a formats_.clear() on close() ?\n\n> >>  \treturn 0;\n> >>  }\n> >>\n> >> @@ -178,6 +185,25 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)\n> >>  \treturn setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);\n> >>  }\n> >>\n> >> +/**\n> >> + * \\brief List the sub-device image resolutions and formats on \\a pad\n\ns/List/Retrieve/ ?\n\n> >> + * \\param[in] pad The 0-indexed pad number to enumerate formats on\n\n\"to retrieve formats for\" ?\n\n> >> + *\n> >> + * \\return A vector of image formats, or an empty vector if the pad does not\n> >> + * exist\n> >> + */\n> >> +std::vector<V4L2SubdeviceFormat> &V4L2Subdevice::formats(unsigned int pad)\n> >> +{\n> >> +\t/*\n> >> +\t * If pad does not exist, return an empty vector at position\n> >> +\t * pads().size()\n> >> +\t */\n\nThis will prevent differentiating between a non-existing pad and a pad\nthat has no format. How about returning a pointer instead of a reference\n?\n\n> >> +\tif (pad > entity_->pads().size())\n> >> +\t\tpad = entity_->pads().size();\n> >> +\n> >> +\treturn formats_[pad];\n> >> +}\n> >> +\n> >>  /**\n> >>   * \\brief Retrieve the image format set on one of the V4L2 subdevice pads\n> >>   * \\param[in] pad The 0-indexed pad number the format is to be retrieved from\n> >> @@ -242,6 +268,98 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n> >>  \treturn 0;\n> >>  }\n> >>\n> >> +int V4L2Subdevice::listPadSizes(unsigned int pad, unsigned int mbus_code,\n> >> +\t\t\t\tstd::vector<V4L2SubdeviceFormat> *formats)\n> >> +{\n> >> +\tstruct v4l2_subdev_frame_size_enum sizeEnum = {};\n> >> +\tint ret;\n> >> +\n> >> +\tsizeEnum.index = 0;\n> >> +\tsizeEnum.pad = pad;\n> >> +\tsizeEnum.code = mbus_code;\n> >> +\tsizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> >> +\n> >> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum))) {\n\nAssignments in conditional expressions are discouraged. How about\n\n\twhile (1) {\n\t\tret = ioctl(...);\n\t\tif (ret < 0)\n\t\t\tbreak;\n\n> >> +\t\tV4L2SubdeviceFormat minFormat = {\n> >> +\t\t\t.mbus_code = mbus_code,\n> >> +\t\t\t.width = sizeEnum.min_width,\n> >> +\t\t\t.height = sizeEnum.min_height,\n> >> +\t\t};\n> >> +\t\tformats->push_back(minFormat);\n\nYou can use emplace_back() instead of creating a local temporary\nvariable.\n\n> >> +\n> >> +\t\t/*\n> >> +\t\t * Most subdevices report discrete frame resolutions, where\n> >> +\t\t * min and max sizes are identical. For continue frame\n> >> +\t\t * resolutions, store the min and max sizes interval.\n> >> +\t\t */\n\nThat's a bit of a hack. How is a caller supposed to tell if two\nconsecutive entries in the list are min, max values or discrete values ?\nHow about creating a SizeRange class (in geometry.h) to store min and\nmax width and height, and using a std::vector<SizeRange> ? That would\nalso have the benefit of not storing the mbus code in all entries.\n\n> >> +\t\tif (sizeEnum.min_width == sizeEnum.max_width &&\n> >> +\t\t    sizeEnum.min_height == sizeEnum.max_height) {\n> >> +\t\t\tsizeEnum.index++;\n> >> +\t\t\tcontinue;\n> >> +\t\t}\n> >> +\n> >> +\t\tV4L2SubdeviceFormat maxFormat = {\n> >> +\t\t\t.mbus_code = mbus_code,\n> >> +\t\t\t.width = sizeEnum.max_width,\n> >> +\t\t\t.height = sizeEnum.max_height,\n> >> +\t\t};\n> >> +\t\tformats->push_back(maxFormat);\n\nemplace_back() here too.\n\n> >> +\n> >> +\t\tsizeEnum.index++;\n> >> +\t}\n> >> +\n> >> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> >> +\t\tLOG(V4L2Subdev, Error)\n> >> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> >> +\t\t\t<< \" of \" << deviceName() << \": \"\n> >> +\t\t\t<< strerror(errno);\n> >> +\t\treturn ret;\n> >> +\t}\n> >> +\n> >> +\treturn 0;\n> >> +}\n> >> +\n> >> +std::vector<V4L2SubdeviceFormat> V4L2Subdevice::listPadFormats(unsigned int pad)\n> >> +{\n> >> +\tstruct v4l2_subdev_mbus_code_enum mbusEnum = {};\n> >> +\tstd::vector<V4L2SubdeviceFormat> formats = {};\n> >> +\tint ret;\n> >> +\n> >> +\tmbusEnum.pad = pad;\n> >> +\tmbusEnum.index = 0;\n> >> +\tmbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> >> +\n> >> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum))) {\n\nSame comment here.\n\n> >> +\t\tret = listPadSizes(pad, mbusEnum.code, &formats);\n\nHow about making format a std::map<unsigned int, std:vector<SizeRange>>\nto store the mbus code ?\n\n> >> +\t\tif (ret)\n> >> +\t\t\treturn formats;\n> >> +\n> >> +\t\tmbusEnum.index++;\n> >> +\t}\n> >> +\n> >> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> >> +\t\tLOG(V4L2Subdev, Error)\n> >> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> >> +\t\t\t<< \" of \" << deviceName() << \": \" << strerror(-ret);\n> >> +\t\treturn formats;\n> >> +\t}\n> >> +\n> >> +\tif (mbusEnum.index == 0 && ret && errno == EINVAL) {\n> >> +\t\t/*\n> >> +\t\t * The subdevice might not support ENUM_MBUS_CODE but\n> >> +\t\t * might support ENUM_FRAME_SIZES.\n> >> +\t\t */\n\nCan that happen ?\n\n> >> +\t\tstruct V4L2SubdeviceFormat subdevFormat;\n> >> +\t\tret = getFormat(pad, &subdevFormat);\n> >> +\t\tif (ret)\n> >> +\t\t\treturn formats;\n> >> +\n> >> +\t\tlistPadSizes(pad, subdevFormat.mbus_code, &formats);\n> >> +\t}\n> >> +\n> >> +\treturn formats;\n> >> +}\n> >> +\n> >>  int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,\n> >>  \t\t\t\tRectangle *rect)\n> >>  {","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 64A4B610B3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 27 Feb 2019 18:51:27 +0100 (CET)","from pendragon.ideasonboard.com (unknown [83.145.195.18])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A192749;\n\tWed, 27 Feb 2019 18:51:26 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1551289886;\n\tbh=zipSNXObTmxdcSkjfZhpnE5n03k/v8zH7COsikGtrWw=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=eHVOzYCLP7LihUz8ZB7h8rnF6quIBeQPuSv0blMBAHB3W/oJ87GOdHIwhWRYA4+Fj\n\tvb2J6u8SB/sEC8zgO+OFZTZUPUxmZUylC1QlVtT81z/k9pyG+SgH13LB9GCXhee7WI\n\tR22V+m34LhLmn8SrBXnQqVxs8gcbdEb4wHODEmfM=","Date":"Wed, 27 Feb 2019 19:51:20 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<20190227175120.GL4813@pendragon.ideasonboard.com>","References":"<20190226162641.12116-1-jacopo@jmondi.org>\n\t<20190226162641.12116-3-jacopo@jmondi.org>\n\t<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>\n\t<20190227081804.3ey5berzsd57534n@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190227081804.3ey5berzsd57534n@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 27 Feb 2019 17:51:27 -0000"}},{"id":940,"web_url":"https://patchwork.libcamera.org/comment/940/","msgid":"<20190228084431.ozg3aste35sma27x@uno.localdomain>","date":"2019-02-28T08:44:31","subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"HI Laurent,\n   thanks for your comments\n\nOn Wed, Feb 27, 2019 at 07:51:20PM +0200, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> Thank you for the patch.\n>\n> On Wed, Feb 27, 2019 at 09:18:04AM +0100, Jacopo Mondi wrote:\n> > On Tue, Feb 26, 2019 at 11:19:40PM +0000, Kieran Bingham wrote:\n> > > On 26/02/2019 16:26, Jacopo Mondi wrote:\n> > >> Implement enumFormat() methods to enumerate the available image\n> > >> resolutions on the subdevice.\n> > >>\n> > >> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > >> ---\n> > >>  src/libcamera/include/v4l2_subdevice.h |   9 ++\n> > >>  src/libcamera/v4l2_subdevice.cpp       | 118 +++++++++++++++++++++++++\n> > >>  2 files changed, 127 insertions(+)\n> > >>\n> > >> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h\n> > >> index eac699a06109..6b21308d2087 100644\n> > >> --- a/src/libcamera/include/v4l2_subdevice.h\n> > >> +++ b/src/libcamera/include/v4l2_subdevice.h\n> > >> @@ -7,7 +7,9 @@\n> > >>  #ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__\n> > >>  #define __LIBCAMERA_V4L2_SUBDEVICE_H__\n> > >>\n> > >> +#include <map>\n> > >>  #include <string>\n> > >> +#include <vector>\n> > >>\n> > >>  #include \"media_object.h\"\n> > >>\n> > >> @@ -38,15 +40,22 @@ public:\n> > >>  \tint setCrop(unsigned int pad, Rectangle *rect);\n> > >>  \tint setCompose(unsigned int pad, Rectangle *rect);\n> > >>\n> > >> +\tstd::vector<V4L2SubdeviceFormat> &formats(unsigned int pad);\n>\n> Shouldn't you return a const reference ? And make this function const ?\n>\n> > >>  \tint getFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> > >>  \tint setFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> > >>\n> > >>  private:\n> > >> +\tint listPadSizes(unsigned int pad, unsigned int mbus_code,\n> > >> +\t\t\t std::vector<V4L2SubdeviceFormat> *formats);\n> > >> +\tstd::vector<V4L2SubdeviceFormat> listPadFormats(unsigned int pad);\n> > >\n> > > The word 'list' seems a bit redundant in 'listPadSizes()' and\n> > > 'listPadFormats()' ... and seems a bit hungarian notation to me?\n> >\n> > I interpreted \"list\" as a verb, so the function name reads like \"list\n> > all formats on a pad\". Is it weird to you?\n>\n> How about s/list/enumerate/ to remove all ambiguity ?\n>\n\nOk\n\n> > > Other than that, I trust that the tests that follow make sure the code\n> > > is doing something sane :)\n> > >\n> > > I can't see anything jump out at me yet.\n> > >\n> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > >\n> > >> +\n> > >>  \tint setSelection(unsigned int pad, unsigned int target,\n> > >>  \t\t\t Rectangle *rect);\n> > >>\n> > >>  \tconst MediaEntity *entity_;\n> > >>  \tint fd_;\n> > >> +\n> > >> +\tstd::map<unsigned int, std::vector<V4L2SubdeviceFormat>> formats_;\n> > >>  };\n> > >>\n> > >>  } /* namespace libcamera */\n> > >> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> > >> index 56ecf3851cb0..f81a521f9e2a 100644\n> > >> --- a/src/libcamera/v4l2_subdevice.cpp\n> > >> +++ b/src/libcamera/v4l2_subdevice.cpp\n> > >> @@ -5,6 +5,10 @@\n> > >>   * v4l2_subdevice.cpp - V4L2 Subdevice\n> > >>   */\n> > >>\n> > >> +#include <map>\n> > >> +#include <string>\n> > >> +#include <vector>\n> > >> +\n>\n> Not strictly needed as the header includes them.\n>\n> > >>  #include <fcntl.h>\n> > >>  #include <string.h>\n> > >>  #include <sys/ioctl.h>\n> > >> @@ -116,6 +120,9 @@ int V4L2Subdevice::open()\n> > >>  \t}\n> > >>  \tfd_ = ret;\n> > >>\n> > >> +\tfor (MediaPad *pad : entity_->pads())\n> > >> +\t\tformats_[pad->index()] = listPadFormats(pad->index());\n> > >> +\n>\n> Should you do a formats_.clear() on close() ?\n>\n\nGood point. But do we want to enumerate formats everytime we open a\nvideo device, or do it once and store them through open/close.\n\nIf I use a pointer to store the format vector (or map as you suggested)\nI can easly find out if that's the first time the subdevice got\nopened, and create the format list once.\n\n> > >>  \treturn 0;\n> > >>  }\n> > >>\n> > >> @@ -178,6 +185,25 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)\n> > >>  \treturn setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);\n> > >>  }\n> > >>\n> > >> +/**\n> > >> + * \\brief List the sub-device image resolutions and formats on \\a pad\n>\n> s/List/Retrieve/ ?\n>\n> > >> + * \\param[in] pad The 0-indexed pad number to enumerate formats on\n>\n> \"to retrieve formats for\" ?\n>\n> > >> + *\n> > >> + * \\return A vector of image formats, or an empty vector if the pad does not\n> > >> + * exist\n> > >> + */\n> > >> +std::vector<V4L2SubdeviceFormat> &V4L2Subdevice::formats(unsigned int pad)\n> > >> +{\n> > >> +\t/*\n> > >> +\t * If pad does not exist, return an empty vector at position\n> > >> +\t * pads().size()\n> > >> +\t */\n>\n> This will prevent differentiating between a non-existing pad and a pad\n> that has no format. How about returning a pointer instead of a reference\n> ?\n\nAck, as per the above point, having the formats as pointers makes it\neasier to find out if they have been ever enumerated or not.\n\n>\n> > >> +\tif (pad > entity_->pads().size())\n> > >> +\t\tpad = entity_->pads().size();\n> > >> +\n> > >> +\treturn formats_[pad];\n> > >> +}\n> > >> +\n> > >>  /**\n> > >>   * \\brief Retrieve the image format set on one of the V4L2 subdevice pads\n> > >>   * \\param[in] pad The 0-indexed pad number the format is to be retrieved from\n> > >> @@ -242,6 +268,98 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n> > >>  \treturn 0;\n> > >>  }\n> > >>\n> > >> +int V4L2Subdevice::listPadSizes(unsigned int pad, unsigned int mbus_code,\n> > >> +\t\t\t\tstd::vector<V4L2SubdeviceFormat> *formats)\n> > >> +{\n> > >> +\tstruct v4l2_subdev_frame_size_enum sizeEnum = {};\n> > >> +\tint ret;\n> > >> +\n> > >> +\tsizeEnum.index = 0;\n> > >> +\tsizeEnum.pad = pad;\n> > >> +\tsizeEnum.code = mbus_code;\n> > >> +\tsizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> > >> +\n> > >> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum))) {\n>\n> Assignments in conditional expressions are discouraged. How about\n\nAre they?\n\n>\n> \twhile (1) {\n> \t\tret = ioctl(...);\n> \t\tif (ret < 0)\n> \t\t\tbreak;\n\nSure, no problem\n\n>\n> > >> +\t\tV4L2SubdeviceFormat minFormat = {\n> > >> +\t\t\t.mbus_code = mbus_code,\n> > >> +\t\t\t.width = sizeEnum.min_width,\n> > >> +\t\t\t.height = sizeEnum.min_height,\n> > >> +\t\t};\n> > >> +\t\tformats->push_back(minFormat);\n>\n> You can use emplace_back() instead of creating a local temporary\n> variable.\n\nThanks. How does that work on structures with only the default\ncompiler-created constructor?\n>\n> > >> +\n> > >> +\t\t/*\n> > >> +\t\t * Most subdevices report discrete frame resolutions, where\n> > >> +\t\t * min and max sizes are identical. For continue frame\n> > >> +\t\t * resolutions, store the min and max sizes interval.\n> > >> +\t\t */\n>\n> That's a bit of a hack. How is a caller supposed to tell if two\n> consecutive entries in the list are min, max values or discrete values ?\n> How about creating a SizeRange class (in geometry.h) to store min and\n> max width and height, and using a std::vector<SizeRange> ? That would\n> also have the benefit of not storing the mbus code in all entries.\n>\n\nIt really puzzled me how to better handle this. If we store min/max as\nwell, how are users of the subdevice expected to handle this? They\nshall be aware that the formats can either be a single format with a\nmin/max range, or an enumeration of discrete sizes. I mean, it's\nsurely doable, I wonder how to express it clearly, in both\ndocumentation and code. It's not unexpected though, as it replicates\nthe SUBDEV_ENUM_FRAME_SIZE behavior, so maybe it's enough to repeat\nthe same here, but I wanted to avoid this ambiguity in our\nimplementation. I guess it's not easily doable.\n\n> > >> +\t\tif (sizeEnum.min_width == sizeEnum.max_width &&\n> > >> +\t\t    sizeEnum.min_height == sizeEnum.max_height) {\n> > >> +\t\t\tsizeEnum.index++;\n> > >> +\t\t\tcontinue;\n> > >> +\t\t}\n> > >> +\n> > >> +\t\tV4L2SubdeviceFormat maxFormat = {\n> > >> +\t\t\t.mbus_code = mbus_code,\n> > >> +\t\t\t.width = sizeEnum.max_width,\n> > >> +\t\t\t.height = sizeEnum.max_height,\n> > >> +\t\t};\n> > >> +\t\tformats->push_back(maxFormat);\n>\n> emplace_back() here too.\n>\n> > >> +\n> > >> +\t\tsizeEnum.index++;\n> > >> +\t}\n> > >> +\n> > >> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> > >> +\t\tLOG(V4L2Subdev, Error)\n> > >> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> > >> +\t\t\t<< \" of \" << deviceName() << \": \"\n> > >> +\t\t\t<< strerror(errno);\n> > >> +\t\treturn ret;\n> > >> +\t}\n> > >> +\n> > >> +\treturn 0;\n> > >> +}\n> > >> +\n> > >> +std::vector<V4L2SubdeviceFormat> V4L2Subdevice::listPadFormats(unsigned int pad)\n> > >> +{\n> > >> +\tstruct v4l2_subdev_mbus_code_enum mbusEnum = {};\n> > >> +\tstd::vector<V4L2SubdeviceFormat> formats = {};\n> > >> +\tint ret;\n> > >> +\n> > >> +\tmbusEnum.pad = pad;\n> > >> +\tmbusEnum.index = 0;\n> > >> +\tmbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> > >> +\n> > >> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum))) {\n>\n> Same comment here.\n>\n> > >> +\t\tret = listPadSizes(pad, mbusEnum.code, &formats);\n>\n> How about making format a std::map<unsigned int, std:vector<SizeRange>>\n> to store the mbus code ?\n>\n\nThat's a good suggestion, I'll try and see how it looks like.\n\n> > >> +\t\tif (ret)\n> > >> +\t\t\treturn formats;\n> > >> +\n> > >> +\t\tmbusEnum.index++;\n> > >> +\t}\n> > >> +\n> > >> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> > >> +\t\tLOG(V4L2Subdev, Error)\n> > >> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> > >> +\t\t\t<< \" of \" << deviceName() << \": \" << strerror(-ret);\n> > >> +\t\treturn formats;\n> > >> +\t}\n> > >> +\n> > >> +\tif (mbusEnum.index == 0 && ret && errno == EINVAL) {\n> > >> +\t\t/*\n> > >> +\t\t * The subdevice might not support ENUM_MBUS_CODE but\n> > >> +\t\t * might support ENUM_FRAME_SIZES.\n> > >> +\t\t */\n>\n> Can that happen ?\n>\n\nIs there anything in the V4L2 APIs preventing this? I haven't find\nanything in the documentation that says so. I would be happy to drop\nthis, if we consider this case non-standard and not worth supporting.\n\nThanks\n  j\n\n> > >> +\t\tstruct V4L2SubdeviceFormat subdevFormat;\n> > >> +\t\tret = getFormat(pad, &subdevFormat);\n> > >> +\t\tif (ret)\n> > >> +\t\t\treturn formats;\n> > >> +\n> > >> +\t\tlistPadSizes(pad, subdevFormat.mbus_code, &formats);\n> > >> +\t}\n> > >> +\n> > >> +\treturn formats;\n> > >> +}\n> > >> +\n> > >>  int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,\n> > >>  \t\t\t\tRectangle *rect)\n> > >>  {\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net\n\t[217.70.183.198])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7E138600FC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Feb 2019 09:44:01 +0100 (CET)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay6-d.mail.gandi.net (Postfix) with ESMTPSA id C1CDDC0011;\n\tThu, 28 Feb 2019 08:44:00 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Thu, 28 Feb 2019 09:44:31 +0100","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<20190228084431.ozg3aste35sma27x@uno.localdomain>","References":"<20190226162641.12116-1-jacopo@jmondi.org>\n\t<20190226162641.12116-3-jacopo@jmondi.org>\n\t<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>\n\t<20190227081804.3ey5berzsd57534n@uno.localdomain>\n\t<20190227175120.GL4813@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"xpxlmixxfrgcosrc\"","Content-Disposition":"inline","In-Reply-To":"<20190227175120.GL4813@pendragon.ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 28 Feb 2019 08:44:01 -0000"}},{"id":956,"web_url":"https://patchwork.libcamera.org/comment/956/","msgid":"<20190228172303.GC7811@pendragon.ideasonboard.com>","date":"2019-02-28T17:23:03","subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Thu, Feb 28, 2019 at 09:44:31AM +0100, Jacopo Mondi wrote:\n> On Wed, Feb 27, 2019 at 07:51:20PM +0200, Laurent Pinchart wrote:\n> > On Wed, Feb 27, 2019 at 09:18:04AM +0100, Jacopo Mondi wrote:\n> >> On Tue, Feb 26, 2019 at 11:19:40PM +0000, Kieran Bingham wrote:\n> >>> On 26/02/2019 16:26, Jacopo Mondi wrote:\n> >>>> Implement enumFormat() methods to enumerate the available image\n> >>>> resolutions on the subdevice.\n> >>>>\n> >>>> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> >>>> ---\n> >>>>  src/libcamera/include/v4l2_subdevice.h |   9 ++\n> >>>>  src/libcamera/v4l2_subdevice.cpp       | 118 +++++++++++++++++++++++++\n> >>>>  2 files changed, 127 insertions(+)\n> >>>>\n> >>>> diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h\n> >>>> index eac699a06109..6b21308d2087 100644\n> >>>> --- a/src/libcamera/include/v4l2_subdevice.h\n> >>>> +++ b/src/libcamera/include/v4l2_subdevice.h\n> >>>> @@ -7,7 +7,9 @@\n> >>>>  #ifndef __LIBCAMERA_V4L2_SUBDEVICE_H__\n> >>>>  #define __LIBCAMERA_V4L2_SUBDEVICE_H__\n> >>>>\n> >>>> +#include <map>\n> >>>>  #include <string>\n> >>>> +#include <vector>\n> >>>>\n> >>>>  #include \"media_object.h\"\n> >>>>\n> >>>> @@ -38,15 +40,22 @@ public:\n> >>>>  \tint setCrop(unsigned int pad, Rectangle *rect);\n> >>>>  \tint setCompose(unsigned int pad, Rectangle *rect);\n> >>>>\n> >>>> +\tstd::vector<V4L2SubdeviceFormat> &formats(unsigned int pad);\n> >\n> > Shouldn't you return a const reference ? And make this function const ?\n> >\n> >>>>  \tint getFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> >>>>  \tint setFormat(unsigned int pad, V4L2SubdeviceFormat *format);\n> >>>>\n> >>>>  private:\n> >>>> +\tint listPadSizes(unsigned int pad, unsigned int mbus_code,\n> >>>> +\t\t\t std::vector<V4L2SubdeviceFormat> *formats);\n> >>>> +\tstd::vector<V4L2SubdeviceFormat> listPadFormats(unsigned int pad);\n> >>>\n> >>> The word 'list' seems a bit redundant in 'listPadSizes()' and\n> >>> 'listPadFormats()' ... and seems a bit hungarian notation to me?\n> >>\n> >> I interpreted \"list\" as a verb, so the function name reads like \"list\n> >> all formats on a pad\". Is it weird to you?\n> >\n> > How about s/list/enumerate/ to remove all ambiguity ?\n> \n> Ok\n> \n> >>> Other than that, I trust that the tests that follow make sure the code\n> >>> is doing something sane :)\n> >>>\n> >>> I can't see anything jump out at me yet.\n> >>>\n> >>> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> >>>\n> >>>> +\n> >>>>  \tint setSelection(unsigned int pad, unsigned int target,\n> >>>>  \t\t\t Rectangle *rect);\n> >>>>\n> >>>>  \tconst MediaEntity *entity_;\n> >>>>  \tint fd_;\n> >>>> +\n> >>>> +\tstd::map<unsigned int, std::vector<V4L2SubdeviceFormat>> formats_;\n> >>>>  };\n> >>>>\n> >>>>  } /* namespace libcamera */\n> >>>> diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp\n> >>>> index 56ecf3851cb0..f81a521f9e2a 100644\n> >>>> --- a/src/libcamera/v4l2_subdevice.cpp\n> >>>> +++ b/src/libcamera/v4l2_subdevice.cpp\n> >>>> @@ -5,6 +5,10 @@\n> >>>>   * v4l2_subdevice.cpp - V4L2 Subdevice\n> >>>>   */\n> >>>>\n> >>>> +#include <map>\n> >>>> +#include <string>\n> >>>> +#include <vector>\n> >>>> +\n> >\n> > Not strictly needed as the header includes them.\n> >\n> >>>>  #include <fcntl.h>\n> >>>>  #include <string.h>\n> >>>>  #include <sys/ioctl.h>\n> >>>> @@ -116,6 +120,9 @@ int V4L2Subdevice::open()\n> >>>>  \t}\n> >>>>  \tfd_ = ret;\n> >>>>\n> >>>> +\tfor (MediaPad *pad : entity_->pads())\n> >>>> +\t\tformats_[pad->index()] = listPadFormats(pad->index());\n> >>>> +\n> >\n> > Should you do a formats_.clear() on close() ?\n> >\n> \n> Good point. But do we want to enumerate formats everytime we open a\n> video device, or do it once and store them through open/close.\n> \n> If I use a pointer to store the format vector (or map as you suggested)\n> I can easly find out if that's the first time the subdevice got\n> opened, and create the format list once.\n> \n> >>>>  \treturn 0;\n> >>>>  }\n> >>>>\n> >>>> @@ -178,6 +185,25 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect)\n> >>>>  \treturn setSelection(pad, V4L2_SEL_TGT_COMPOSE, rect);\n> >>>>  }\n> >>>>\n> >>>> +/**\n> >>>> + * \\brief List the sub-device image resolutions and formats on \\a pad\n> >\n> > s/List/Retrieve/ ?\n> >\n> >>>> + * \\param[in] pad The 0-indexed pad number to enumerate formats on\n> >\n> > \"to retrieve formats for\" ?\n> >\n> >>>> + *\n> >>>> + * \\return A vector of image formats, or an empty vector if the pad does not\n> >>>> + * exist\n> >>>> + */\n> >>>> +std::vector<V4L2SubdeviceFormat> &V4L2Subdevice::formats(unsigned int pad)\n> >>>> +{\n> >>>> +\t/*\n> >>>> +\t * If pad does not exist, return an empty vector at position\n> >>>> +\t * pads().size()\n> >>>> +\t */\n> >\n> > This will prevent differentiating between a non-existing pad and a pad\n> > that has no format. How about returning a pointer instead of a reference\n> > ?\n> \n> Ack, as per the above point, having the formats as pointers makes it\n> easier to find out if they have been ever enumerated or not.\n> \n> >>>> +\tif (pad > entity_->pads().size())\n> >>>> +\t\tpad = entity_->pads().size();\n> >>>> +\n> >>>> +\treturn formats_[pad];\n> >>>> +}\n> >>>> +\n> >>>>  /**\n> >>>>   * \\brief Retrieve the image format set on one of the V4L2 subdevice pads\n> >>>>   * \\param[in] pad The 0-indexed pad number the format is to be retrieved from\n> >>>> @@ -242,6 +268,98 @@ int V4L2Subdevice::setFormat(unsigned int pad, V4L2SubdeviceFormat *format)\n> >>>>  \treturn 0;\n> >>>>  }\n> >>>>\n> >>>> +int V4L2Subdevice::listPadSizes(unsigned int pad, unsigned int mbus_code,\n> >>>> +\t\t\t\tstd::vector<V4L2SubdeviceFormat> *formats)\n> >>>> +{\n> >>>> +\tstruct v4l2_subdev_frame_size_enum sizeEnum = {};\n> >>>> +\tint ret;\n> >>>> +\n> >>>> +\tsizeEnum.index = 0;\n> >>>> +\tsizeEnum.pad = pad;\n> >>>> +\tsizeEnum.code = mbus_code;\n> >>>> +\tsizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> >>>> +\n> >>>> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum))) {\n> >\n> > Assignments in conditional expressions are discouraged. How about\n> \n> Are they?\n\nIt's too easy to forget an = and type = instead of == in a conditional\nexpression, so forbidding assignments makes it easier to catch such\nerrors as they would always be invalid.\n\n> >\n> > \twhile (1) {\n> > \t\tret = ioctl(...);\n> > \t\tif (ret < 0)\n> > \t\t\tbreak;\n> \n> Sure, no problem\n> \n> >>>> +\t\tV4L2SubdeviceFormat minFormat = {\n> >>>> +\t\t\t.mbus_code = mbus_code,\n> >>>> +\t\t\t.width = sizeEnum.min_width,\n> >>>> +\t\t\t.height = sizeEnum.min_height,\n> >>>> +\t\t};\n> >>>> +\t\tformats->push_back(minFormat);\n> >\n> > You can use emplace_back() instead of creating a local temporary\n> > variable.\n> \n> Thanks. How does that work on structures with only the default\n> compiler-created constructor?\n\nI think you can use an initializer list.\n\n> >>>> +\n> >>>> +\t\t/*\n> >>>> +\t\t * Most subdevices report discrete frame resolutions, where\n> >>>> +\t\t * min and max sizes are identical. For continue frame\n> >>>> +\t\t * resolutions, store the min and max sizes interval.\n> >>>> +\t\t */\n> >\n> > That's a bit of a hack. How is a caller supposed to tell if two\n> > consecutive entries in the list are min, max values or discrete values ?\n> > How about creating a SizeRange class (in geometry.h) to store min and\n> > max width and height, and using a std::vector<SizeRange> ? That would\n> > also have the benefit of not storing the mbus code in all entries.\n> \n> It really puzzled me how to better handle this. If we store min/max as\n> well, how are users of the subdevice expected to handle this? They\n> shall be aware that the formats can either be a single format with a\n> min/max range, or an enumeration of discrete sizes. I mean, it's\n> surely doable, I wonder how to express it clearly, in both\n> documentation and code. It's not unexpected though, as it replicates\n> the SUBDEV_ENUM_FRAME_SIZE behavior, so maybe it's enough to repeat\n> the same here, but I wanted to avoid this ambiguity in our\n> implementation. I guess it's not easily doable.\n\nI don't think we can do that easily, and your attempt created an even\nbigger problem :-)\n\n> >>>> +\t\tif (sizeEnum.min_width == sizeEnum.max_width &&\n> >>>> +\t\t    sizeEnum.min_height == sizeEnum.max_height) {\n> >>>> +\t\t\tsizeEnum.index++;\n> >>>> +\t\t\tcontinue;\n> >>>> +\t\t}\n> >>>> +\n> >>>> +\t\tV4L2SubdeviceFormat maxFormat = {\n> >>>> +\t\t\t.mbus_code = mbus_code,\n> >>>> +\t\t\t.width = sizeEnum.max_width,\n> >>>> +\t\t\t.height = sizeEnum.max_height,\n> >>>> +\t\t};\n> >>>> +\t\tformats->push_back(maxFormat);\n> >\n> > emplace_back() here too.\n> >\n> >>>> +\n> >>>> +\t\tsizeEnum.index++;\n> >>>> +\t}\n> >>>> +\n> >>>> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> >>>> +\t\tLOG(V4L2Subdev, Error)\n> >>>> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> >>>> +\t\t\t<< \" of \" << deviceName() << \": \"\n> >>>> +\t\t\t<< strerror(errno);\n> >>>> +\t\treturn ret;\n> >>>> +\t}\n> >>>> +\n> >>>> +\treturn 0;\n> >>>> +}\n> >>>> +\n> >>>> +std::vector<V4L2SubdeviceFormat> V4L2Subdevice::listPadFormats(unsigned int pad)\n> >>>> +{\n> >>>> +\tstruct v4l2_subdev_mbus_code_enum mbusEnum = {};\n> >>>> +\tstd::vector<V4L2SubdeviceFormat> formats = {};\n> >>>> +\tint ret;\n> >>>> +\n> >>>> +\tmbusEnum.pad = pad;\n> >>>> +\tmbusEnum.index = 0;\n> >>>> +\tmbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE;\n> >>>> +\n> >>>> +\twhile (!(ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum))) {\n> >\n> > Same comment here.\n> >\n> >>>> +\t\tret = listPadSizes(pad, mbusEnum.code, &formats);\n> >\n> > How about making format a std::map<unsigned int, std:vector<SizeRange>>\n> > to store the mbus code ?\n> \n> That's a good suggestion, I'll try and see how it looks like.\n> \n> >>>> +\t\tif (ret)\n> >>>> +\t\t\treturn formats;\n> >>>> +\n> >>>> +\t\tmbusEnum.index++;\n> >>>> +\t}\n> >>>> +\n> >>>> +\tif (ret && (errno != EINVAL && errno != ENOTTY)) {\n> >>>> +\t\tLOG(V4L2Subdev, Error)\n> >>>> +\t\t\t<< \"Unable to enumerate format on pad \" << pad\n> >>>> +\t\t\t<< \" of \" << deviceName() << \": \" << strerror(-ret);\n> >>>> +\t\treturn formats;\n> >>>> +\t}\n> >>>> +\n> >>>> +\tif (mbusEnum.index == 0 && ret && errno == EINVAL) {\n> >>>> +\t\t/*\n> >>>> +\t\t * The subdevice might not support ENUM_MBUS_CODE but\n> >>>> +\t\t * might support ENUM_FRAME_SIZES.\n> >>>> +\t\t */\n> >\n> > Can that happen ?\n> \n> Is there anything in the V4L2 APIs preventing this? I haven't find\n> anything in the documentation that says so. I would be happy to drop\n> this, if we consider this case non-standard and not worth supporting.\n\nI think it would be a case of non-compliance, so I don't think we need\nto support it.\n\n> >>>> +\t\tstruct V4L2SubdeviceFormat subdevFormat;\n> >>>> +\t\tret = getFormat(pad, &subdevFormat);\n> >>>> +\t\tif (ret)\n> >>>> +\t\t\treturn formats;\n> >>>> +\n> >>>> +\t\tlistPadSizes(pad, subdevFormat.mbus_code, &formats);\n> >>>> +\t}\n> >>>> +\n> >>>> +\treturn formats;\n> >>>> +}\n> >>>> +\n> >>>>  int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target,\n> >>>>  \t\t\t\tRectangle *rect)\n> >>>>  {","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B884A610B6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 28 Feb 2019 18:23:09 +0100 (CET)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1835B49;\n\tThu, 28 Feb 2019 18:23:09 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1551374589;\n\tbh=ZAXoxrFY7MGJ74eOQig0NpFnJWnEeFcO0nLNGAuZHzI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=QX5eGNTT0kU+IMsk9ZGhcFFwXsYHxJ5sKfSh9hptjlPjqwfUeAssMQ83QU8OTWcSR\n\tG2VOh+eV99bcbpu2tqcfz2yqleBomWXk0U4OluRn3Ag1or7C7zBUwqMjr9MVUtCeIQ\n\tqVbzszpMaLCzRnrZXvYJyhACIz2DS45vjrLttq/c=","Date":"Thu, 28 Feb 2019 19:23:03 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"Kieran Bingham <kieran.bingham@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<20190228172303.GC7811@pendragon.ideasonboard.com>","References":"<20190226162641.12116-1-jacopo@jmondi.org>\n\t<20190226162641.12116-3-jacopo@jmondi.org>\n\t<fc93ca43-cfd7-153c-56a8-3e28c331fb7a@ideasonboard.com>\n\t<20190227081804.3ey5berzsd57534n@uno.localdomain>\n\t<20190227175120.GL4813@pendragon.ideasonboard.com>\n\t<20190228084431.ozg3aste35sma27x@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190228084431.ozg3aste35sma27x@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 2/8] libcamera: v4l2_subdevice:\n\tImplement ENUM_FRAME_SIZES","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 28 Feb 2019 17:23:09 -0000"}}]