[{"id":24754,"web_url":"https://patchwork.libcamera.org/comment/24754/","msgid":"<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>","date":"2022-08-24T06:37:59","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":86,"url":"https://patchwork.libcamera.org/api/people/86/","name":"Umang Jain","email":"umang.jain@ideasonboard.com"},"content":"Hi Laurent,\n\nThank you for the patch.\n\nOn 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n> Add a ColorSpace:fromString() function to parse a string into a color\n> space. The string can either contain the name of a well-known color\n> space, or four color space components separate by a '/' character.\n\nI don't see the order of four components separated by '/' - documented \nin the codebase.\nShould we document the string order as well?\n\n'''\nThe string representation of the colorspace separated by '/' is as follows:\n     <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n'''\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\nReviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n> ---\n>   include/libcamera/color_space.h |   2 +\n>   src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n>   2 files changed, 121 insertions(+), 30 deletions(-)\n>\n> diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n> index 8030a264c66f..f493f72d2db8 100644\n> --- a/include/libcamera/color_space.h\n> +++ b/include/libcamera/color_space.h\n> @@ -59,6 +59,8 @@ public:\n>   \n>   \tstd::string toString() const;\n>   \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n> +\n> +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n>   };\n>   \n>   bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n> diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n> index 1b2dd2404452..5233626f5ae9 100644\n> --- a/src/libcamera/color_space.cpp\n> +++ b/src/libcamera/color_space.cpp\n> @@ -12,6 +12,9 @@\n>   #include <map>\n>   #include <sstream>\n>   #include <utility>\n> +#include <vector>\n> +\n> +#include <libcamera/base/utils.h>\n>   \n>   /**\n>    * \\file color_space.h\n> @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n>    * \\brief The pixel range used with by color space\n>    */\n>   \n> +namespace {\n> +\n> +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> +\t{ ColorSpace::Raw, \"RAW\" },\n> +\t{ ColorSpace::Srgb, \"sRGB\" },\n> +\t{ ColorSpace::Sycc, \"sYCC\" },\n> +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> +\t{ ColorSpace::Rec709, \"Rec709\" },\n> +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> +} };\n> +\n> +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n> +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n> +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n> +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n> +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n> +};\n> +\n> +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n> +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n> +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n> +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n> +};\n> +\n> +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n> +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n> +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n> +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n> +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n> +};\n> +\n> +const std::map<ColorSpace::Range, std::string> rangeNames = {\n> +\t{ ColorSpace::Range::Full, \"Full\" },\n> +\t{ ColorSpace::Range::Limited, \"Limited\" },\n> +};\n> +\n> +} /* namespace */\n> +\n>   /**\n>    * \\brief Assemble and return a readable string representation of the\n>    * ColorSpace\n> @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n>   {\n>   \t/* Print out a brief name only for standard color spaces. */\n>   \n> -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> -\t\t{ ColorSpace::Raw, \"RAW\" },\n> -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n> -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n> -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n> -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> -\t} };\n>   \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n>   \t\t\t       [this](const auto &item) {\n>   \t\t\t\t       return *this == item.first;\n> @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n>   \n>   \t/* Assemble a name made of the constituent fields. */\n>   \n> -\tstatic const std::map<Primaries, std::string> primariesNames = {\n> -\t\t{ Primaries::Raw, \"RAW\" },\n> -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n> -\t\t{ Primaries::Rec709, \"Rec709\" },\n> -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n> -\t};\n> -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n> -\t\t{ TransferFunction::Linear, \"Linear\" },\n> -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n> -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n> -\t};\n> -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n> -\t\t{ YcbcrEncoding::None, \"None\" },\n> -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n> -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n> -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n> -\t};\n> -\tstatic const std::map<Range, std::string> rangeNames = {\n> -\t\t{ Range::Full, \"Full\" },\n> -\t\t{ Range::Limited, \"Limited\" },\n> -\t};\n> -\n>   \tauto itPrimaries = primariesNames.find(primaries);\n>   \tstd::string primariesName =\n>   \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n> @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n>   \treturn colorSpace->toString();\n>   }\n>   \n> +/**\n> + * \\brief Construct a color space from a string\n> + * \\param[in] str The string\n> + *\n> + * The string \\a str can contain the name of a well-known color space, or be\n> + * made of the four color space components separate by a '/' character. Any\n> + * failure to parse the string, either because it doesn't match the expected\n> + * format, or because the one of the names isn't recognized, will cause this\n> + * function to return std::nullopt.\n> + *\n> + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n> + * string doesn't describe a known color space\n> + */\n> +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n> +{\n> +\t/* First search for a standard color space name match. */\n> +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> +\t\t\t\t\t [&str](const auto &item) {\n> +\t\t\t\t\t\t return str == item.second;\n> +\t\t\t\t\t });\n> +\tif (itColorSpace != colorSpaceNames.end())\n> +\t\treturn itColorSpace->first;\n> +\n> +\t/*\n> +\t * If not found, the string must contain the four color space\n> +\t * components separated by a '/' character.\n> +\t */\n> +\tconst auto &split = utils::split(str, \"/\");\n> +\tstd::vector<std::string> components{ split.begin(), split.end() };\n> +\n> +\tif (components.size() != 4)\n> +\t\treturn std::nullopt;\n> +\n> +\tColorSpace colorSpace = ColorSpace::Raw;\n> +\n> +\t/* Color primaries */\n> +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n> +\t\t\t\t\t[&components](const auto &item) {\n> +\t\t\t\t\t\treturn components[0] == item.second;\n> +\t\t\t\t\t});\n> +\tif (itPrimaries == primariesNames.end())\n> +\t\treturn std::nullopt;\n> +\n> +\tcolorSpace.primaries = itPrimaries->first;\n> +\n> +\t/* Transfer function */\n> +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n> +\t\t\t\t       [&components](const auto &item) {\n> +\t\t\t\t\t       return components[1] == item.second;\n> +\t\t\t\t       });\n> +\tif (itTransfer == transferNames.end())\n> +\t\treturn std::nullopt;\n> +\n> +\tcolorSpace.transferFunction = itTransfer->first;\n> +\n> +\t/* YCbCr encoding */\n> +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n> +\t\t\t\t       [&components](const auto &item) {\n> +\t\t\t\t\t       return components[2] == item.second;\n> +\t\t\t\t       });\n> +\tif (itEncoding == encodingNames.end())\n> +\t\treturn std::nullopt;\n> +\n> +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n> +\n> +\t/* Quantization range */\n> +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n> +\t\t\t\t    [&components](const auto &item) {\n> +\t\t\t\t\t    return components[3] == item.second;\n> +\t\t\t\t    });\n> +\tif (itRange == rangeNames.end())\n> +\t\treturn std::nullopt;\n> +\n> +\tcolorSpace.range = itRange->first;\n> +\n> +\treturn colorSpace;\n> +}\n> +\n>   /**\n>    * \\brief Compare color spaces for equality\n>    * \\return True if the two color spaces are identical, false otherwise","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A9FA8C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 24 Aug 2022 06:38:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2C7F761FBD;\n\tWed, 24 Aug 2022 08:38:05 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6012661FA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 24 Aug 2022 08:38:04 +0200 (CEST)","from [IPV6:2401:4900:1f3f:806e:6647:8e5c:f441:ca9a] (unknown\n\t[IPv6:2401:4900:1f3f:806e:6647:8e5c:f441:ca9a])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 671F22B3;\n\tWed, 24 Aug 2022 08:38:03 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661323085;\n\tbh=xWAJAqwTOBqlZKNHbFsVwOJ/yxoOUF8gIcJJ2M46XtI=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=ggYZRAj/aYjYA9vfKqwaG3jzrETQMZGSt8HoaCGhobgfctnu3RPpHhoj3+V4joYjR\n\t+XC9u4h97R9nsR1UgPsARbLPY0z5e3yX2+nuT21D9RnHyhT9Sof9UpDAi1sfVb03Mf\n\tNMevVl5InkNu7EFRbW17dGNu5XW647tO3DmxfZEW2K5f1ptuIKM3IIoaDiKlTSfWAU\n\txGHWqBi8jo9BKBJXPSsHvJ1SwfzXTGKklgo3W/7ICV5vcwyX8pDy8AaKOaIjYwej2m\n\tE8Z7kxKBDEsUYU12tCRS3yY9Qi28Td30wRStd9keJdE3B2Sc2zgOgYWg/zY9GWFxwS\n\tbfpeKia9hb1TA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661323083;\n\tbh=xWAJAqwTOBqlZKNHbFsVwOJ/yxoOUF8gIcJJ2M46XtI=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=tIMJBeEG5xpjCKIIA6Te+AjuLP2K1NvwKeWxrboa2W0tAyLc5D1nnkv538E6cfWZ+\n\t87b0rRIZMJt/b9TxTp/3Q+l4Lv8C+5AgIivN+m2nIfDM+F69PLtHG1Hv0aimMXAYlP\n\tAM/ua/QH3hXA7DXGWOcVdEXVq8ycebkWmB5Ln7GI="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"tIMJBeEG\"; dkim-atps=neutral","Message-ID":"<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>","Date":"Wed, 24 Aug 2022 12:07:59 +0530","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.12.0","Content-Language":"en-US","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>","In-Reply-To":"<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Umang Jain via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Umang Jain <umang.jain@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24759,"web_url":"https://patchwork.libcamera.org/comment/24759/","msgid":"<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>","date":"2022-08-24T09:40:59","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Umang,\n\nOn Wed, Aug 24, 2022 at 12:07:59PM +0530, Umang Jain wrote:\n> On 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n> > Add a ColorSpace:fromString() function to parse a string into a color\n> > space. The string can either contain the name of a well-known color\n> > space, or four color space components separate by a '/' character.\n> \n> I don't see the order of four components separated by '/' - documented \n> in the codebase.\n> Should we document the string order as well?\n> \n> '''\n> The string representation of the colorspace separated by '/' is as follows:\n>      <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n> '''\n\nI'll expand the documentation of the function to make this more\nexplicit.\n\nI'm also wondering (warning, bikeshedding ahead) if the '/'-separated\nformat is the best option. GStreamer uses colons to separate the\ncomponents, and only accepts numerical values for the components in that\ncase. I'm not aware of (but haven't looked for) alternatives.\n\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> \n> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n> \n> > ---\n> >   include/libcamera/color_space.h |   2 +\n> >   src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n> >   2 files changed, 121 insertions(+), 30 deletions(-)\n> >\n> > diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n> > index 8030a264c66f..f493f72d2db8 100644\n> > --- a/include/libcamera/color_space.h\n> > +++ b/include/libcamera/color_space.h\n> > @@ -59,6 +59,8 @@ public:\n> >   \n> >   \tstd::string toString() const;\n> >   \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n> > +\n> > +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n> >   };\n> >   \n> >   bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n> > diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n> > index 1b2dd2404452..5233626f5ae9 100644\n> > --- a/src/libcamera/color_space.cpp\n> > +++ b/src/libcamera/color_space.cpp\n> > @@ -12,6 +12,9 @@\n> >   #include <map>\n> >   #include <sstream>\n> >   #include <utility>\n> > +#include <vector>\n> > +\n> > +#include <libcamera/base/utils.h>\n> >   \n> >   /**\n> >    * \\file color_space.h\n> > @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n> >    * \\brief The pixel range used with by color space\n> >    */\n> >   \n> > +namespace {\n> > +\n> > +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> > +\t{ ColorSpace::Raw, \"RAW\" },\n> > +\t{ ColorSpace::Srgb, \"sRGB\" },\n> > +\t{ ColorSpace::Sycc, \"sYCC\" },\n> > +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> > +\t{ ColorSpace::Rec709, \"Rec709\" },\n> > +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> > +} };\n> > +\n> > +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n> > +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n> > +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n> > +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n> > +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n> > +};\n> > +\n> > +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n> > +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n> > +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n> > +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n> > +};\n> > +\n> > +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n> > +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n> > +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n> > +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n> > +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n> > +};\n> > +\n> > +const std::map<ColorSpace::Range, std::string> rangeNames = {\n> > +\t{ ColorSpace::Range::Full, \"Full\" },\n> > +\t{ ColorSpace::Range::Limited, \"Limited\" },\n> > +};\n> > +\n> > +} /* namespace */\n> > +\n> >   /**\n> >    * \\brief Assemble and return a readable string representation of the\n> >    * ColorSpace\n> > @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n> >   {\n> >   \t/* Print out a brief name only for standard color spaces. */\n> >   \n> > -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> > -\t\t{ ColorSpace::Raw, \"RAW\" },\n> > -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n> > -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n> > -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> > -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n> > -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> > -\t} };\n> >   \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> >   \t\t\t       [this](const auto &item) {\n> >   \t\t\t\t       return *this == item.first;\n> > @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n> >   \n> >   \t/* Assemble a name made of the constituent fields. */\n> >   \n> > -\tstatic const std::map<Primaries, std::string> primariesNames = {\n> > -\t\t{ Primaries::Raw, \"RAW\" },\n> > -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n> > -\t\t{ Primaries::Rec709, \"Rec709\" },\n> > -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n> > -\t};\n> > -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n> > -\t\t{ TransferFunction::Linear, \"Linear\" },\n> > -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n> > -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n> > -\t};\n> > -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n> > -\t\t{ YcbcrEncoding::None, \"None\" },\n> > -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n> > -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n> > -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n> > -\t};\n> > -\tstatic const std::map<Range, std::string> rangeNames = {\n> > -\t\t{ Range::Full, \"Full\" },\n> > -\t\t{ Range::Limited, \"Limited\" },\n> > -\t};\n> > -\n> >   \tauto itPrimaries = primariesNames.find(primaries);\n> >   \tstd::string primariesName =\n> >   \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n> > @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n> >   \treturn colorSpace->toString();\n> >   }\n> >   \n> > +/**\n> > + * \\brief Construct a color space from a string\n> > + * \\param[in] str The string\n> > + *\n> > + * The string \\a str can contain the name of a well-known color space, or be\n> > + * made of the four color space components separate by a '/' character. Any\n> > + * failure to parse the string, either because it doesn't match the expected\n> > + * format, or because the one of the names isn't recognized, will cause this\n> > + * function to return std::nullopt.\n> > + *\n> > + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n> > + * string doesn't describe a known color space\n> > + */\n> > +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n> > +{\n> > +\t/* First search for a standard color space name match. */\n> > +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> > +\t\t\t\t\t [&str](const auto &item) {\n> > +\t\t\t\t\t\t return str == item.second;\n> > +\t\t\t\t\t });\n> > +\tif (itColorSpace != colorSpaceNames.end())\n> > +\t\treturn itColorSpace->first;\n> > +\n> > +\t/*\n> > +\t * If not found, the string must contain the four color space\n> > +\t * components separated by a '/' character.\n> > +\t */\n> > +\tconst auto &split = utils::split(str, \"/\");\n> > +\tstd::vector<std::string> components{ split.begin(), split.end() };\n> > +\n> > +\tif (components.size() != 4)\n> > +\t\treturn std::nullopt;\n> > +\n> > +\tColorSpace colorSpace = ColorSpace::Raw;\n> > +\n> > +\t/* Color primaries */\n> > +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n> > +\t\t\t\t\t[&components](const auto &item) {\n> > +\t\t\t\t\t\treturn components[0] == item.second;\n> > +\t\t\t\t\t});\n> > +\tif (itPrimaries == primariesNames.end())\n> > +\t\treturn std::nullopt;\n> > +\n> > +\tcolorSpace.primaries = itPrimaries->first;\n> > +\n> > +\t/* Transfer function */\n> > +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n> > +\t\t\t\t       [&components](const auto &item) {\n> > +\t\t\t\t\t       return components[1] == item.second;\n> > +\t\t\t\t       });\n> > +\tif (itTransfer == transferNames.end())\n> > +\t\treturn std::nullopt;\n> > +\n> > +\tcolorSpace.transferFunction = itTransfer->first;\n> > +\n> > +\t/* YCbCr encoding */\n> > +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n> > +\t\t\t\t       [&components](const auto &item) {\n> > +\t\t\t\t\t       return components[2] == item.second;\n> > +\t\t\t\t       });\n> > +\tif (itEncoding == encodingNames.end())\n> > +\t\treturn std::nullopt;\n> > +\n> > +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n> > +\n> > +\t/* Quantization range */\n> > +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n> > +\t\t\t\t    [&components](const auto &item) {\n> > +\t\t\t\t\t    return components[3] == item.second;\n> > +\t\t\t\t    });\n> > +\tif (itRange == rangeNames.end())\n> > +\t\treturn std::nullopt;\n> > +\n> > +\tcolorSpace.range = itRange->first;\n> > +\n> > +\treturn colorSpace;\n> > +}\n> > +\n> >   /**\n> >    * \\brief Compare color spaces for equality\n> >    * \\return True if the two color spaces are identical, false otherwise","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id CCEC7C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 24 Aug 2022 09:41:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3C75161FBC;\n\tWed, 24 Aug 2022 11:41:07 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0DA9761FA2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 24 Aug 2022 11:41:05 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5820B2B3;\n\tWed, 24 Aug 2022 11:41:04 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661334067;\n\tbh=mF42pIYWSUe7aWX03g3jzqdp6QCnIT4+TKvPjChCU6M=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=KggZ7cdnz8//8iC4fUqWSDHQ9OIy6a4qltwbpJrwjFqwfciidfiiXfBo0cB3aKTE1\n\t3hdyVScKUazSGgRzBmdgd9ILYwNACT+1VqwVFZfaH/Sf0BVdY5RiBYurssm4LFzaCb\n\t5gfygSAg4zv8eoACwKMOJtvssY9UYTX59jaRnpOMqfrl0F0o8r+xp2kn6y7iJMm6Rt\n\t0nQhm8G5fuSyQsGeq8gLLCy0dZQMcTAexaItpSo9OVsJKUTbYT8lDDajsdXFgBoTw5\n\tmBSQbzLHMBuFiSetuCXc6j7v4/wsc5+EZIj+ma2FPDqf1TT7Vq/Cg4IlrZhU6ZrlM9\n\tof4btrXaixIDQ==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661334064;\n\tbh=mF42pIYWSUe7aWX03g3jzqdp6QCnIT4+TKvPjChCU6M=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=o6nUOUMJh7fRGViWRc2NbnRMqBEGJhiuHKfuviZZeRWkDPhclR+1ua/FxfQQwH5Q3\n\tH/Vow4DPvWgbwU05XeC9s0vhPA8WeSZ5ToiDIGh2X4ZiJSLnYjdtHSeaATsk/Kr7d9\n\tyXbGK+byAoJj7R0MhNTJYiBE4sjW/gTkbKoFz1VA="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"o6nUOUMJ\"; dkim-atps=neutral","Date":"Wed, 24 Aug 2022 12:40:59 +0300","To":"Umang Jain <umang.jain@ideasonboard.com>","Message-ID":"<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>\n\t<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24763,"web_url":"https://patchwork.libcamera.org/comment/24763/","msgid":"<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>","date":"2022-08-24T21:32:18","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Aug 24, 2022 at 12:40:59PM +0300, Laurent Pinchart via libcamera-devel wrote:\n> On Wed, Aug 24, 2022 at 12:07:59PM +0530, Umang Jain wrote:\n> > On 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n> > > Add a ColorSpace:fromString() function to parse a string into a color\n> > > space. The string can either contain the name of a well-known color\n> > > space, or four color space components separate by a '/' character.\n> > \n> > I don't see the order of four components separated by '/' - documented \n> > in the codebase.\n> > Should we document the string order as well?\n> > \n> > '''\n> > The string representation of the colorspace separated by '/' is as follows:\n> >      <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n> > '''\n> \n> I'll expand the documentation of the function to make this more\n> explicit.\n> \n> I'm also wondering (warning, bikeshedding ahead) if the '/'-separated\n> format is the best option. GStreamer uses colons to separate the\n> components, and only accepts numerical values for the components in that\n> case. I'm not aware of (but haven't looked for) alternatives.\n\nBy the way, the '/'-separated format comes from toString(). If we want\nto change it, we should update the toString() function as well.\n\n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > \n> > Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n> > \n> > > ---\n> > >   include/libcamera/color_space.h |   2 +\n> > >   src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n> > >   2 files changed, 121 insertions(+), 30 deletions(-)\n> > >\n> > > diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n> > > index 8030a264c66f..f493f72d2db8 100644\n> > > --- a/include/libcamera/color_space.h\n> > > +++ b/include/libcamera/color_space.h\n> > > @@ -59,6 +59,8 @@ public:\n> > >   \n> > >   \tstd::string toString() const;\n> > >   \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n> > > +\n> > > +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n> > >   };\n> > >   \n> > >   bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n> > > diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n> > > index 1b2dd2404452..5233626f5ae9 100644\n> > > --- a/src/libcamera/color_space.cpp\n> > > +++ b/src/libcamera/color_space.cpp\n> > > @@ -12,6 +12,9 @@\n> > >   #include <map>\n> > >   #include <sstream>\n> > >   #include <utility>\n> > > +#include <vector>\n> > > +\n> > > +#include <libcamera/base/utils.h>\n> > >   \n> > >   /**\n> > >    * \\file color_space.h\n> > > @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n> > >    * \\brief The pixel range used with by color space\n> > >    */\n> > >   \n> > > +namespace {\n> > > +\n> > > +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> > > +\t{ ColorSpace::Raw, \"RAW\" },\n> > > +\t{ ColorSpace::Srgb, \"sRGB\" },\n> > > +\t{ ColorSpace::Sycc, \"sYCC\" },\n> > > +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> > > +\t{ ColorSpace::Rec709, \"Rec709\" },\n> > > +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> > > +} };\n> > > +\n> > > +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n> > > +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n> > > +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n> > > +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n> > > +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n> > > +};\n> > > +\n> > > +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n> > > +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n> > > +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n> > > +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n> > > +};\n> > > +\n> > > +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n> > > +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n> > > +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n> > > +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n> > > +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n> > > +};\n> > > +\n> > > +const std::map<ColorSpace::Range, std::string> rangeNames = {\n> > > +\t{ ColorSpace::Range::Full, \"Full\" },\n> > > +\t{ ColorSpace::Range::Limited, \"Limited\" },\n> > > +};\n> > > +\n> > > +} /* namespace */\n> > > +\n> > >   /**\n> > >    * \\brief Assemble and return a readable string representation of the\n> > >    * ColorSpace\n> > > @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n> > >   {\n> > >   \t/* Print out a brief name only for standard color spaces. */\n> > >   \n> > > -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> > > -\t\t{ ColorSpace::Raw, \"RAW\" },\n> > > -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n> > > -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n> > > -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> > > -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n> > > -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> > > -\t} };\n> > >   \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> > >   \t\t\t       [this](const auto &item) {\n> > >   \t\t\t\t       return *this == item.first;\n> > > @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n> > >   \n> > >   \t/* Assemble a name made of the constituent fields. */\n> > >   \n> > > -\tstatic const std::map<Primaries, std::string> primariesNames = {\n> > > -\t\t{ Primaries::Raw, \"RAW\" },\n> > > -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n> > > -\t\t{ Primaries::Rec709, \"Rec709\" },\n> > > -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n> > > -\t};\n> > > -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n> > > -\t\t{ TransferFunction::Linear, \"Linear\" },\n> > > -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n> > > -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n> > > -\t};\n> > > -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n> > > -\t\t{ YcbcrEncoding::None, \"None\" },\n> > > -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n> > > -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n> > > -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n> > > -\t};\n> > > -\tstatic const std::map<Range, std::string> rangeNames = {\n> > > -\t\t{ Range::Full, \"Full\" },\n> > > -\t\t{ Range::Limited, \"Limited\" },\n> > > -\t};\n> > > -\n> > >   \tauto itPrimaries = primariesNames.find(primaries);\n> > >   \tstd::string primariesName =\n> > >   \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n> > > @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n> > >   \treturn colorSpace->toString();\n> > >   }\n> > >   \n> > > +/**\n> > > + * \\brief Construct a color space from a string\n> > > + * \\param[in] str The string\n> > > + *\n> > > + * The string \\a str can contain the name of a well-known color space, or be\n> > > + * made of the four color space components separate by a '/' character. Any\n> > > + * failure to parse the string, either because it doesn't match the expected\n> > > + * format, or because the one of the names isn't recognized, will cause this\n> > > + * function to return std::nullopt.\n> > > + *\n> > > + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n> > > + * string doesn't describe a known color space\n> > > + */\n> > > +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n> > > +{\n> > > +\t/* First search for a standard color space name match. */\n> > > +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> > > +\t\t\t\t\t [&str](const auto &item) {\n> > > +\t\t\t\t\t\t return str == item.second;\n> > > +\t\t\t\t\t });\n> > > +\tif (itColorSpace != colorSpaceNames.end())\n> > > +\t\treturn itColorSpace->first;\n> > > +\n> > > +\t/*\n> > > +\t * If not found, the string must contain the four color space\n> > > +\t * components separated by a '/' character.\n> > > +\t */\n> > > +\tconst auto &split = utils::split(str, \"/\");\n> > > +\tstd::vector<std::string> components{ split.begin(), split.end() };\n> > > +\n> > > +\tif (components.size() != 4)\n> > > +\t\treturn std::nullopt;\n> > > +\n> > > +\tColorSpace colorSpace = ColorSpace::Raw;\n> > > +\n> > > +\t/* Color primaries */\n> > > +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n> > > +\t\t\t\t\t[&components](const auto &item) {\n> > > +\t\t\t\t\t\treturn components[0] == item.second;\n> > > +\t\t\t\t\t});\n> > > +\tif (itPrimaries == primariesNames.end())\n> > > +\t\treturn std::nullopt;\n> > > +\n> > > +\tcolorSpace.primaries = itPrimaries->first;\n> > > +\n> > > +\t/* Transfer function */\n> > > +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n> > > +\t\t\t\t       [&components](const auto &item) {\n> > > +\t\t\t\t\t       return components[1] == item.second;\n> > > +\t\t\t\t       });\n> > > +\tif (itTransfer == transferNames.end())\n> > > +\t\treturn std::nullopt;\n> > > +\n> > > +\tcolorSpace.transferFunction = itTransfer->first;\n> > > +\n> > > +\t/* YCbCr encoding */\n> > > +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n> > > +\t\t\t\t       [&components](const auto &item) {\n> > > +\t\t\t\t\t       return components[2] == item.second;\n> > > +\t\t\t\t       });\n> > > +\tif (itEncoding == encodingNames.end())\n> > > +\t\treturn std::nullopt;\n> > > +\n> > > +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n> > > +\n> > > +\t/* Quantization range */\n> > > +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n> > > +\t\t\t\t    [&components](const auto &item) {\n> > > +\t\t\t\t\t    return components[3] == item.second;\n> > > +\t\t\t\t    });\n> > > +\tif (itRange == rangeNames.end())\n> > > +\t\treturn std::nullopt;\n> > > +\n> > > +\tcolorSpace.range = itRange->first;\n> > > +\n> > > +\treturn colorSpace;\n> > > +}\n> > > +\n> > >   /**\n> > >    * \\brief Compare color spaces for equality\n> > >    * \\return True if the two color spaces are identical, false otherwise","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 467F6C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 24 Aug 2022 21:32:27 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 498BE61FC1;\n\tWed, 24 Aug 2022 23:32:26 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 558A560E25\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 24 Aug 2022 23:32:24 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8BEE62B3;\n\tWed, 24 Aug 2022 23:32:23 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661376746;\n\tbh=wue7dws9j8ErcH4u+jn4rfH7bZnDwHDfwSP/j3MefEo=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=hS/S0QgquWXAGMy6/rVDC2z8Jah6kt/YBbPjGkQYDcUqddABCFMltCoNLxBJINFmG\n\tvSIo54q8mZsr1V55oWV2DeMyYX3WwNwdnLL6AB8fd+bu8/sQ8BoRDdz25lT4m6Z5uw\n\tiIJDOkbrngXtpHrtQJatb2y89Y3prcW8nfaevh2JHAfmjT+TWQg0KMPyvOnDbe9Eed\n\tkcX7vJnN3/nUDJ+H99TUBAb+oWk+CUb4jyhUEmqbDvurv0xh+8YTN9FY6TftcoBi4w\n\t5k4U6rf4suoomlKGVZdwdOJbWbr+yiqjoI1H67cSJFLMIjw7n7eWUMqMJnI/OJA58D\n\tTJrRlvvfLQr8Q==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661376743;\n\tbh=wue7dws9j8ErcH4u+jn4rfH7bZnDwHDfwSP/j3MefEo=;\n\th=Date:From:To:Subject:References:In-Reply-To:From;\n\tb=QzgWFf3u+EIMuPOk0bvdxu99g7supU9fkR8d8iyiNiRFeMnAyvhfExOQ3CeftZ1ij\n\tfHfOKdrWxyeOBnNJMLb56t3Ak1xcjWDBxMKeA1fuMAe1Cf297IZqt6+TI/BduRunR9\n\tSSZaEIivRikh1JrqaCv7LWJajBmDyTpagwXGheFY="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"QzgWFf3u\"; dkim-atps=neutral","Date":"Thu, 25 Aug 2022 00:32:18 +0300","To":"Umang Jain <umang.jain@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Message-ID":"<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>\n\t<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>\n\t<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24769,"web_url":"https://patchwork.libcamera.org/comment/24769/","msgid":"<ae8213b5-2b9e-4225-c75e-921f2e7825b6@ideasonboard.com>","date":"2022-08-25T13:19:53","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":86,"url":"https://patchwork.libcamera.org/api/people/86/","name":"Umang Jain","email":"umang.jain@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 8/25/22 3:02 AM, Laurent Pinchart wrote:\n> On Wed, Aug 24, 2022 at 12:40:59PM +0300, Laurent Pinchart via libcamera-devel wrote:\n>> On Wed, Aug 24, 2022 at 12:07:59PM +0530, Umang Jain wrote:\n>>> On 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n>>>> Add a ColorSpace:fromString() function to parse a string into a color\n>>>> space. The string can either contain the name of a well-known color\n>>>> space, or four color space components separate by a '/' character.\n>>> I don't see the order of four components separated by '/' - documented\n>>> in the codebase.\n>>> Should we document the string order as well?\n>>>\n>>> '''\n>>> The string representation of the colorspace separated by '/' is as follows:\n>>>       <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n>>> '''\n>> I'll expand the documentation of the function to make this more\n>> explicit.\n\nThank you!\n>>\n>> I'm also wondering (warning, bikeshedding ahead) if the '/'-separated\n>> format is the best option. GStreamer uses colons to separate the\n>> components, and only accepts numerical values for the components in that\n>> case. I'm not aware of (but haven't looked for) alternatives.\n\nOh, so we can't really align with gstreamer using the colon(':') because \nit would split awkwardly with utils::split(str, \":\")  I think\n\nColorSpace::Primaries::Rec709:ColorSpace::TransferFunction::Rec709:ColorSpace::YcbcrEncoding::Rec709:ColorSpace::Range::Full\n\nIn that case, I think \"/\" is our best choice. Second best I think will \nbe \"|\"\n\nI saw a few Colorspace::toString() randomly on the internet, but none \nwere structural. They were mostly just meant to print it out for logs \n(and not treating as string input).\n\nI also saw DRM also has colorspaces but haven't came across a helper \nlike we need. I am not sure if it's worth to look further! \"/\" is \nalready a good starting point, given our requirements.\n> By the way, the '/'-separated format comes from toString(). If we want\n> to change it, we should update the toString() function as well.\n\nAck.\n>\n>>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>>> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n>>>\n>>>> ---\n>>>>    include/libcamera/color_space.h |   2 +\n>>>>    src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n>>>>    2 files changed, 121 insertions(+), 30 deletions(-)\n>>>>\n>>>> diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n>>>> index 8030a264c66f..f493f72d2db8 100644\n>>>> --- a/include/libcamera/color_space.h\n>>>> +++ b/include/libcamera/color_space.h\n>>>> @@ -59,6 +59,8 @@ public:\n>>>>    \n>>>>    \tstd::string toString() const;\n>>>>    \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n>>>> +\n>>>> +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n>>>>    };\n>>>>    \n>>>>    bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n>>>> diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n>>>> index 1b2dd2404452..5233626f5ae9 100644\n>>>> --- a/src/libcamera/color_space.cpp\n>>>> +++ b/src/libcamera/color_space.cpp\n>>>> @@ -12,6 +12,9 @@\n>>>>    #include <map>\n>>>>    #include <sstream>\n>>>>    #include <utility>\n>>>> +#include <vector>\n>>>> +\n>>>> +#include <libcamera/base/utils.h>\n>>>>    \n>>>>    /**\n>>>>     * \\file color_space.h\n>>>> @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n>>>>     * \\brief The pixel range used with by color space\n>>>>     */\n>>>>    \n>>>> +namespace {\n>>>> +\n>>>> +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n>>>> +\t{ ColorSpace::Raw, \"RAW\" },\n>>>> +\t{ ColorSpace::Srgb, \"sRGB\" },\n>>>> +\t{ ColorSpace::Sycc, \"sYCC\" },\n>>>> +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n>>>> +\t{ ColorSpace::Rec709, \"Rec709\" },\n>>>> +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n>>>> +} };\n>>>> +\n>>>> +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n>>>> +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n>>>> +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n>>>> +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n>>>> +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n>>>> +};\n>>>> +\n>>>> +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n>>>> +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n>>>> +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n>>>> +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n>>>> +};\n>>>> +\n>>>> +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n>>>> +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n>>>> +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n>>>> +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n>>>> +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n>>>> +};\n>>>> +\n>>>> +const std::map<ColorSpace::Range, std::string> rangeNames = {\n>>>> +\t{ ColorSpace::Range::Full, \"Full\" },\n>>>> +\t{ ColorSpace::Range::Limited, \"Limited\" },\n>>>> +};\n>>>> +\n>>>> +} /* namespace */\n>>>> +\n>>>>    /**\n>>>>     * \\brief Assemble and return a readable string representation of the\n>>>>     * ColorSpace\n>>>> @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n>>>>    {\n>>>>    \t/* Print out a brief name only for standard color spaces. */\n>>>>    \n>>>> -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n>>>> -\t\t{ ColorSpace::Raw, \"RAW\" },\n>>>> -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n>>>> -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n>>>> -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n>>>> -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n>>>> -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n>>>> -\t} };\n>>>>    \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n>>>>    \t\t\t       [this](const auto &item) {\n>>>>    \t\t\t\t       return *this == item.first;\n>>>> @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n>>>>    \n>>>>    \t/* Assemble a name made of the constituent fields. */\n>>>>    \n>>>> -\tstatic const std::map<Primaries, std::string> primariesNames = {\n>>>> -\t\t{ Primaries::Raw, \"RAW\" },\n>>>> -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n>>>> -\t\t{ Primaries::Rec709, \"Rec709\" },\n>>>> -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n>>>> -\t};\n>>>> -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n>>>> -\t\t{ TransferFunction::Linear, \"Linear\" },\n>>>> -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n>>>> -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n>>>> -\t};\n>>>> -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n>>>> -\t\t{ YcbcrEncoding::None, \"None\" },\n>>>> -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n>>>> -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n>>>> -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n>>>> -\t};\n>>>> -\tstatic const std::map<Range, std::string> rangeNames = {\n>>>> -\t\t{ Range::Full, \"Full\" },\n>>>> -\t\t{ Range::Limited, \"Limited\" },\n>>>> -\t};\n>>>> -\n>>>>    \tauto itPrimaries = primariesNames.find(primaries);\n>>>>    \tstd::string primariesName =\n>>>>    \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n>>>> @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n>>>>    \treturn colorSpace->toString();\n>>>>    }\n>>>>    \n>>>> +/**\n>>>> + * \\brief Construct a color space from a string\n>>>> + * \\param[in] str The string\n>>>> + *\n>>>> + * The string \\a str can contain the name of a well-known color space, or be\n>>>> + * made of the four color space components separate by a '/' character. Any\n>>>> + * failure to parse the string, either because it doesn't match the expected\n>>>> + * format, or because the one of the names isn't recognized, will cause this\n>>>> + * function to return std::nullopt.\n>>>> + *\n>>>> + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n>>>> + * string doesn't describe a known color space\n>>>> + */\n>>>> +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n>>>> +{\n>>>> +\t/* First search for a standard color space name match. */\n>>>> +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n>>>> +\t\t\t\t\t [&str](const auto &item) {\n>>>> +\t\t\t\t\t\t return str == item.second;\n>>>> +\t\t\t\t\t });\n>>>> +\tif (itColorSpace != colorSpaceNames.end())\n>>>> +\t\treturn itColorSpace->first;\n>>>> +\n>>>> +\t/*\n>>>> +\t * If not found, the string must contain the four color space\n>>>> +\t * components separated by a '/' character.\n>>>> +\t */\n>>>> +\tconst auto &split = utils::split(str, \"/\");\n>>>> +\tstd::vector<std::string> components{ split.begin(), split.end() };\n>>>> +\n>>>> +\tif (components.size() != 4)\n>>>> +\t\treturn std::nullopt;\n>>>> +\n>>>> +\tColorSpace colorSpace = ColorSpace::Raw;\n>>>> +\n>>>> +\t/* Color primaries */\n>>>> +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n>>>> +\t\t\t\t\t[&components](const auto &item) {\n>>>> +\t\t\t\t\t\treturn components[0] == item.second;\n>>>> +\t\t\t\t\t});\n>>>> +\tif (itPrimaries == primariesNames.end())\n>>>> +\t\treturn std::nullopt;\n>>>> +\n>>>> +\tcolorSpace.primaries = itPrimaries->first;\n>>>> +\n>>>> +\t/* Transfer function */\n>>>> +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n>>>> +\t\t\t\t       [&components](const auto &item) {\n>>>> +\t\t\t\t\t       return components[1] == item.second;\n>>>> +\t\t\t\t       });\n>>>> +\tif (itTransfer == transferNames.end())\n>>>> +\t\treturn std::nullopt;\n>>>> +\n>>>> +\tcolorSpace.transferFunction = itTransfer->first;\n>>>> +\n>>>> +\t/* YCbCr encoding */\n>>>> +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n>>>> +\t\t\t\t       [&components](const auto &item) {\n>>>> +\t\t\t\t\t       return components[2] == item.second;\n>>>> +\t\t\t\t       });\n>>>> +\tif (itEncoding == encodingNames.end())\n>>>> +\t\treturn std::nullopt;\n>>>> +\n>>>> +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n>>>> +\n>>>> +\t/* Quantization range */\n>>>> +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n>>>> +\t\t\t\t    [&components](const auto &item) {\n>>>> +\t\t\t\t\t    return components[3] == item.second;\n>>>> +\t\t\t\t    });\n>>>> +\tif (itRange == rangeNames.end())\n>>>> +\t\treturn std::nullopt;\n>>>> +\n>>>> +\tcolorSpace.range = itRange->first;\n>>>> +\n>>>> +\treturn colorSpace;\n>>>> +}\n>>>> +\n>>>>    /**\n>>>>     * \\brief Compare color spaces for equality\n>>>>     * \\return True if the two color spaces are identical, false otherwise","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id BD0D3C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 25 Aug 2022 13:20:00 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0237761FBF;\n\tThu, 25 Aug 2022 15:20:00 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9F34E61FA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 25 Aug 2022 15:19:58 +0200 (CEST)","from [IPV6:2401:4900:1f3f:806e:6647:8e5c:f441:ca9a] (unknown\n\t[IPv6:2401:4900:1f3f:806e:6647:8e5c:f441:ca9a])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 92BFD2B3;\n\tThu, 25 Aug 2022 15:19:57 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661433600;\n\tbh=OEor7wSfB38BcrmF+ZUKoC8DgL1/Z3TCFO1A1yz8BnI=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=sVQ2a0CqKoMKRpWZrEi1X8bTFPCDqxZaUUljAc1UDLHzLAK1XmFmBddRaIv0CsjJf\n\t/A6SH88AjzBnDPu/PX4aWoW0eCbipScwr5OziJTuf495QgJHA8wa+/r5kK1YeWXYEt\n\tO07USgRyKhVKVsNzMRfTzh37UMRZiUCDXyeccBgG0f8AXYa3Vn7cj3oyx+c5m/FEvx\n\tQcUBTQCeat+39KXc91sZEbQjnvQQC8df3Tg02PS6daO/DHdq/SOyUvYiorhskltvnV\n\tawrRG+GVf5drMwAWOSgWNrR7v1f6mH2WgxtYU30m44TGkgTC39kiyfvbqLDEOIRPWN\n\tsWegZJE4InBGg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661433598;\n\tbh=OEor7wSfB38BcrmF+ZUKoC8DgL1/Z3TCFO1A1yz8BnI=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=WtNsrpBaWLB/xAnYtjPhckjSS21CWn6feXesLYMu+UUKz6q3+nKgkso8vRCX2FPmK\n\t0xDGZwcxZZJ3Ri72qmM0iPWYwPr1Ld0cQeOedkYW34HZ5hsXuet4E906vPv1vw0N9y\n\tH48efXD8/heHowWkTJwwndZe5+/Io1kT/bPqON7c="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"WtNsrpBa\"; dkim-atps=neutral","Message-ID":"<ae8213b5-2b9e-4225-c75e-921f2e7825b6@ideasonboard.com>","Date":"Thu, 25 Aug 2022 18:49:53 +0530","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.12.0","Content-Language":"en-US","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>\n\t<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>\n\t<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>\n\t<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>","In-Reply-To":"<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Umang Jain via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Umang Jain <umang.jain@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24770,"web_url":"https://patchwork.libcamera.org/comment/24770/","msgid":"<YweJBuv95NHOX3Qi@pendragon.ideasonboard.com>","date":"2022-08-25T14:36:54","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Umang,\n\nOn Thu, Aug 25, 2022 at 06:49:53PM +0530, Umang Jain wrote:\n> On 8/25/22 3:02 AM, Laurent Pinchart wrote:\n> > On Wed, Aug 24, 2022 at 12:40:59PM +0300, Laurent Pinchart via libcamera-devel wrote:\n> >> On Wed, Aug 24, 2022 at 12:07:59PM +0530, Umang Jain wrote:\n> >>> On 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n> >>>> Add a ColorSpace:fromString() function to parse a string into a color\n> >>>> space. The string can either contain the name of a well-known color\n> >>>> space, or four color space components separate by a '/' character.\n> >>> \n> >>> I don't see the order of four components separated by '/' - documented\n> >>> in the codebase.\n> >>> Should we document the string order as well?\n> >>>\n> >>> '''\n> >>> The string representation of the colorspace separated by '/' is as follows:\n> >>>       <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n> >>> '''\n> >> \n> >> I'll expand the documentation of the function to make this more\n> >> explicit.\n> \n> Thank you!\n> \n> >> I'm also wondering (warning, bikeshedding ahead) if the '/'-separated\n> >> format is the best option. GStreamer uses colons to separate the\n> >> components, and only accepts numerical values for the components in that\n> >> case. I'm not aware of (but haven't looked for) alternatives.\n> \n> Oh, so we can't really align with gstreamer using the colon(':') because \n> it would split awkwardly with utils::split(str, \":\")  I think\n> \n> ColorSpace::Primaries::Rec709:ColorSpace::TransferFunction::Rec709:ColorSpace::YcbcrEncoding::Rec709:ColorSpace::Range::Full\n\nThe string doesn't have to fully qualify the components, it would be\n\n\tRec709:Rec709:Rec709:Full\n\n> In that case, I think \"/\" is our best choice. Second best I think will \n> be \"|\"\n> \n> I saw a few Colorspace::toString() randomly on the internet, but none \n> were structural. They were mostly just meant to print it out for logs \n> (and not treating as string input).\n> \n> I also saw DRM also has colorspaces but haven't came across a helper \n> like we need. I am not sure if it's worth to look further! \"/\" is \n> already a good starting point, given our requirements.\n> \n> > By the way, the '/'-separated format comes from toString(). If we want\n> > to change it, we should update the toString() function as well.\n> \n> Ack.\n> \n> >>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >>> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n> >>>\n> >>>> ---\n> >>>>    include/libcamera/color_space.h |   2 +\n> >>>>    src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n> >>>>    2 files changed, 121 insertions(+), 30 deletions(-)\n> >>>>\n> >>>> diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n> >>>> index 8030a264c66f..f493f72d2db8 100644\n> >>>> --- a/include/libcamera/color_space.h\n> >>>> +++ b/include/libcamera/color_space.h\n> >>>> @@ -59,6 +59,8 @@ public:\n> >>>>    \n> >>>>    \tstd::string toString() const;\n> >>>>    \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n> >>>> +\n> >>>> +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n> >>>>    };\n> >>>>    \n> >>>>    bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n> >>>> diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n> >>>> index 1b2dd2404452..5233626f5ae9 100644\n> >>>> --- a/src/libcamera/color_space.cpp\n> >>>> +++ b/src/libcamera/color_space.cpp\n> >>>> @@ -12,6 +12,9 @@\n> >>>>    #include <map>\n> >>>>    #include <sstream>\n> >>>>    #include <utility>\n> >>>> +#include <vector>\n> >>>> +\n> >>>> +#include <libcamera/base/utils.h>\n> >>>>    \n> >>>>    /**\n> >>>>     * \\file color_space.h\n> >>>> @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n> >>>>     * \\brief The pixel range used with by color space\n> >>>>     */\n> >>>>    \n> >>>> +namespace {\n> >>>> +\n> >>>> +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> >>>> +\t{ ColorSpace::Raw, \"RAW\" },\n> >>>> +\t{ ColorSpace::Srgb, \"sRGB\" },\n> >>>> +\t{ ColorSpace::Sycc, \"sYCC\" },\n> >>>> +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> >>>> +\t{ ColorSpace::Rec709, \"Rec709\" },\n> >>>> +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> >>>> +} };\n> >>>> +\n> >>>> +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n> >>>> +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n> >>>> +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n> >>>> +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n> >>>> +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n> >>>> +};\n> >>>> +\n> >>>> +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n> >>>> +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n> >>>> +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n> >>>> +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n> >>>> +};\n> >>>> +\n> >>>> +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n> >>>> +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n> >>>> +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n> >>>> +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n> >>>> +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n> >>>> +};\n> >>>> +\n> >>>> +const std::map<ColorSpace::Range, std::string> rangeNames = {\n> >>>> +\t{ ColorSpace::Range::Full, \"Full\" },\n> >>>> +\t{ ColorSpace::Range::Limited, \"Limited\" },\n> >>>> +};\n> >>>> +\n> >>>> +} /* namespace */\n> >>>> +\n> >>>>    /**\n> >>>>     * \\brief Assemble and return a readable string representation of the\n> >>>>     * ColorSpace\n> >>>> @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n> >>>>    {\n> >>>>    \t/* Print out a brief name only for standard color spaces. */\n> >>>>    \n> >>>> -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> >>>> -\t\t{ ColorSpace::Raw, \"RAW\" },\n> >>>> -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n> >>>> -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n> >>>> -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> >>>> -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n> >>>> -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> >>>> -\t} };\n> >>>>    \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> >>>>    \t\t\t       [this](const auto &item) {\n> >>>>    \t\t\t\t       return *this == item.first;\n> >>>> @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n> >>>>    \n> >>>>    \t/* Assemble a name made of the constituent fields. */\n> >>>>    \n> >>>> -\tstatic const std::map<Primaries, std::string> primariesNames = {\n> >>>> -\t\t{ Primaries::Raw, \"RAW\" },\n> >>>> -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n> >>>> -\t\t{ Primaries::Rec709, \"Rec709\" },\n> >>>> -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n> >>>> -\t};\n> >>>> -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n> >>>> -\t\t{ TransferFunction::Linear, \"Linear\" },\n> >>>> -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n> >>>> -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n> >>>> -\t};\n> >>>> -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n> >>>> -\t\t{ YcbcrEncoding::None, \"None\" },\n> >>>> -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n> >>>> -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n> >>>> -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n> >>>> -\t};\n> >>>> -\tstatic const std::map<Range, std::string> rangeNames = {\n> >>>> -\t\t{ Range::Full, \"Full\" },\n> >>>> -\t\t{ Range::Limited, \"Limited\" },\n> >>>> -\t};\n> >>>> -\n> >>>>    \tauto itPrimaries = primariesNames.find(primaries);\n> >>>>    \tstd::string primariesName =\n> >>>>    \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n> >>>> @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n> >>>>    \treturn colorSpace->toString();\n> >>>>    }\n> >>>>    \n> >>>> +/**\n> >>>> + * \\brief Construct a color space from a string\n> >>>> + * \\param[in] str The string\n> >>>> + *\n> >>>> + * The string \\a str can contain the name of a well-known color space, or be\n> >>>> + * made of the four color space components separate by a '/' character. Any\n> >>>> + * failure to parse the string, either because it doesn't match the expected\n> >>>> + * format, or because the one of the names isn't recognized, will cause this\n> >>>> + * function to return std::nullopt.\n> >>>> + *\n> >>>> + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n> >>>> + * string doesn't describe a known color space\n> >>>> + */\n> >>>> +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n> >>>> +{\n> >>>> +\t/* First search for a standard color space name match. */\n> >>>> +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> >>>> +\t\t\t\t\t [&str](const auto &item) {\n> >>>> +\t\t\t\t\t\t return str == item.second;\n> >>>> +\t\t\t\t\t });\n> >>>> +\tif (itColorSpace != colorSpaceNames.end())\n> >>>> +\t\treturn itColorSpace->first;\n> >>>> +\n> >>>> +\t/*\n> >>>> +\t * If not found, the string must contain the four color space\n> >>>> +\t * components separated by a '/' character.\n> >>>> +\t */\n> >>>> +\tconst auto &split = utils::split(str, \"/\");\n> >>>> +\tstd::vector<std::string> components{ split.begin(), split.end() };\n> >>>> +\n> >>>> +\tif (components.size() != 4)\n> >>>> +\t\treturn std::nullopt;\n> >>>> +\n> >>>> +\tColorSpace colorSpace = ColorSpace::Raw;\n> >>>> +\n> >>>> +\t/* Color primaries */\n> >>>> +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n> >>>> +\t\t\t\t\t[&components](const auto &item) {\n> >>>> +\t\t\t\t\t\treturn components[0] == item.second;\n> >>>> +\t\t\t\t\t});\n> >>>> +\tif (itPrimaries == primariesNames.end())\n> >>>> +\t\treturn std::nullopt;\n> >>>> +\n> >>>> +\tcolorSpace.primaries = itPrimaries->first;\n> >>>> +\n> >>>> +\t/* Transfer function */\n> >>>> +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n> >>>> +\t\t\t\t       [&components](const auto &item) {\n> >>>> +\t\t\t\t\t       return components[1] == item.second;\n> >>>> +\t\t\t\t       });\n> >>>> +\tif (itTransfer == transferNames.end())\n> >>>> +\t\treturn std::nullopt;\n> >>>> +\n> >>>> +\tcolorSpace.transferFunction = itTransfer->first;\n> >>>> +\n> >>>> +\t/* YCbCr encoding */\n> >>>> +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n> >>>> +\t\t\t\t       [&components](const auto &item) {\n> >>>> +\t\t\t\t\t       return components[2] == item.second;\n> >>>> +\t\t\t\t       });\n> >>>> +\tif (itEncoding == encodingNames.end())\n> >>>> +\t\treturn std::nullopt;\n> >>>> +\n> >>>> +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n> >>>> +\n> >>>> +\t/* Quantization range */\n> >>>> +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n> >>>> +\t\t\t\t    [&components](const auto &item) {\n> >>>> +\t\t\t\t\t    return components[3] == item.second;\n> >>>> +\t\t\t\t    });\n> >>>> +\tif (itRange == rangeNames.end())\n> >>>> +\t\treturn std::nullopt;\n> >>>> +\n> >>>> +\tcolorSpace.range = itRange->first;\n> >>>> +\n> >>>> +\treturn colorSpace;\n> >>>> +}\n> >>>> +\n> >>>>    /**\n> >>>>     * \\brief Compare color spaces for equality\n> >>>>     * \\return True if the two color spaces are identical, false otherwise","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id EE91FC3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 25 Aug 2022 14:37:04 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 16B4161FBF;\n\tThu, 25 Aug 2022 16:37:04 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 22F7B61FA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 25 Aug 2022 16:37:02 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 646BB2B3;\n\tThu, 25 Aug 2022 16:37:01 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661438224;\n\tbh=8zGHj2xt58OAnl+l6f1/LhodjH/naYMv4ypky6yEJaI=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=ulnxSYRH3Q1NF/gHDMpdDn5gVDzM7se/O67PTijhAeCq1zqv/eSCcqZD+eCosJm7Y\n\twvdwyPOXIrisYvH7RzosqYx3CQya3VIhWt1dGRtCdInsr24SWuX3TLqBGJyca/hjkf\n\tj9VJvK2HFrHX6LCdTL9B6hCRohbgSN3ZF5aKeDMubY9UB/AJUudWWDsae1z6DirWAO\n\tWoDzE3dIg6iqsCebzLmjJFHBb8IV23canBA7MQ2VhTZrfdvJJGYx/ULcP3PCmDVRzT\n\t5IsGBYQ61MLmWQOsKbLfzKt3DOYk5GBoeCNtdxORmiTieuEXfohK1868+cFse2MIXd\n\t2Ds/LlnIv/G8A==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661438221;\n\tbh=8zGHj2xt58OAnl+l6f1/LhodjH/naYMv4ypky6yEJaI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=bk73G79G7Ecvb/i5JhrY3W5iE4XvxMjMDr6f6kqNGpa81MAv7jehZR/SjlnjvH6Ql\n\tbLu4d8gHqtGhL/Y2fJv+zMbDvvZZZTlkoExWqFBGfq0DXDWYtR+Vh7xDVjIQqFn7oo\n\t5w/80AKtvMiYY3ZBJtvxCMwpEPfLH7qfJtAPRRmA="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"bk73G79G\"; dkim-atps=neutral","Date":"Thu, 25 Aug 2022 17:36:54 +0300","To":"Umang Jain <umang.jain@ideasonboard.com>","Message-ID":"<YweJBuv95NHOX3Qi@pendragon.ideasonboard.com>","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>\n\t<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>\n\t<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>\n\t<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>\n\t<ae8213b5-2b9e-4225-c75e-921f2e7825b6@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<ae8213b5-2b9e-4225-c75e-921f2e7825b6@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24772,"web_url":"https://patchwork.libcamera.org/comment/24772/","msgid":"<75f43528-901e-841b-6411-e549e0749be9@ideasonboard.com>","date":"2022-08-25T15:43:02","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":86,"url":"https://patchwork.libcamera.org/api/people/86/","name":"Umang Jain","email":"umang.jain@ideasonboard.com"},"content":"On 8/25/22 8:06 PM, Laurent Pinchart wrote:\n> Hi Umang,\n>\n> On Thu, Aug 25, 2022 at 06:49:53PM +0530, Umang Jain wrote:\n>> On 8/25/22 3:02 AM, Laurent Pinchart wrote:\n>>> On Wed, Aug 24, 2022 at 12:40:59PM +0300, Laurent Pinchart via libcamera-devel wrote:\n>>>> On Wed, Aug 24, 2022 at 12:07:59PM +0530, Umang Jain wrote:\n>>>>> On 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n>>>>>> Add a ColorSpace:fromString() function to parse a string into a color\n>>>>>> space. The string can either contain the name of a well-known color\n>>>>>> space, or four color space components separate by a '/' character.\n>>>>> I don't see the order of four components separated by '/' - documented\n>>>>> in the codebase.\n>>>>> Should we document the string order as well?\n>>>>>\n>>>>> '''\n>>>>> The string representation of the colorspace separated by '/' is as follows:\n>>>>>        <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n>>>>> '''\n>>>> I'll expand the documentation of the function to make this more\n>>>> explicit.\n>> Thank you!\n>>\n>>>> I'm also wondering (warning, bikeshedding ahead) if the '/'-separated\n>>>> format is the best option. GStreamer uses colons to separate the\n>>>> components, and only accepts numerical values for the components in that\n>>>> case. I'm not aware of (but haven't looked for) alternatives.\n>> Oh, so we can't really align with gstreamer using the colon(':') because\n>> it would split awkwardly with utils::split(str, \":\")  I think\n>>\n>> ColorSpace::Primaries::Rec709:ColorSpace::TransferFunction::Rec709:ColorSpace::YcbcrEncoding::Rec709:ColorSpace::Range::Full\n> The string doesn't have to fully qualify the components, it would be\n>\n> \tRec709:Rec709:Rec709:Full\n\nYes correct, it can be - Can we keep \":\" as the splitter then?  ;-)\n>\n>> In that case, I think \"/\" is our best choice. Second best I think will\n>> be \"|\"\n>>\n>> I saw a few Colorspace::toString() randomly on the internet, but none\n>> were structural. They were mostly just meant to print it out for logs\n>> (and not treating as string input).\n>>\n>> I also saw DRM also has colorspaces but haven't came across a helper\n>> like we need. I am not sure if it's worth to look further! \"/\" is\n>> already a good starting point, given our requirements.\n>>\n>>> By the way, the '/'-separated format comes from toString(). If we want\n>>> to change it, we should update the toString() function as well.\n>> Ack.\n>>\n>>>>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>>>>> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n>>>>>\n>>>>>> ---\n>>>>>>     include/libcamera/color_space.h |   2 +\n>>>>>>     src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n>>>>>>     2 files changed, 121 insertions(+), 30 deletions(-)\n>>>>>>\n>>>>>> diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n>>>>>> index 8030a264c66f..f493f72d2db8 100644\n>>>>>> --- a/include/libcamera/color_space.h\n>>>>>> +++ b/include/libcamera/color_space.h\n>>>>>> @@ -59,6 +59,8 @@ public:\n>>>>>>     \n>>>>>>     \tstd::string toString() const;\n>>>>>>     \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n>>>>>> +\n>>>>>> +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n>>>>>>     };\n>>>>>>     \n>>>>>>     bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n>>>>>> diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n>>>>>> index 1b2dd2404452..5233626f5ae9 100644\n>>>>>> --- a/src/libcamera/color_space.cpp\n>>>>>> +++ b/src/libcamera/color_space.cpp\n>>>>>> @@ -12,6 +12,9 @@\n>>>>>>     #include <map>\n>>>>>>     #include <sstream>\n>>>>>>     #include <utility>\n>>>>>> +#include <vector>\n>>>>>> +\n>>>>>> +#include <libcamera/base/utils.h>\n>>>>>>     \n>>>>>>     /**\n>>>>>>      * \\file color_space.h\n>>>>>> @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n>>>>>>      * \\brief The pixel range used with by color space\n>>>>>>      */\n>>>>>>     \n>>>>>> +namespace {\n>>>>>> +\n>>>>>> +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n>>>>>> +\t{ ColorSpace::Raw, \"RAW\" },\n>>>>>> +\t{ ColorSpace::Srgb, \"sRGB\" },\n>>>>>> +\t{ ColorSpace::Sycc, \"sYCC\" },\n>>>>>> +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n>>>>>> +\t{ ColorSpace::Rec709, \"Rec709\" },\n>>>>>> +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n>>>>>> +} };\n>>>>>> +\n>>>>>> +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n>>>>>> +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n>>>>>> +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n>>>>>> +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n>>>>>> +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n>>>>>> +};\n>>>>>> +\n>>>>>> +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n>>>>>> +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n>>>>>> +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n>>>>>> +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n>>>>>> +};\n>>>>>> +\n>>>>>> +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n>>>>>> +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n>>>>>> +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n>>>>>> +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n>>>>>> +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n>>>>>> +};\n>>>>>> +\n>>>>>> +const std::map<ColorSpace::Range, std::string> rangeNames = {\n>>>>>> +\t{ ColorSpace::Range::Full, \"Full\" },\n>>>>>> +\t{ ColorSpace::Range::Limited, \"Limited\" },\n>>>>>> +};\n>>>>>> +\n>>>>>> +} /* namespace */\n>>>>>> +\n>>>>>>     /**\n>>>>>>      * \\brief Assemble and return a readable string representation of the\n>>>>>>      * ColorSpace\n>>>>>> @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n>>>>>>     {\n>>>>>>     \t/* Print out a brief name only for standard color spaces. */\n>>>>>>     \n>>>>>> -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n>>>>>> -\t\t{ ColorSpace::Raw, \"RAW\" },\n>>>>>> -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n>>>>>> -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n>>>>>> -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n>>>>>> -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n>>>>>> -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n>>>>>> -\t} };\n>>>>>>     \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n>>>>>>     \t\t\t       [this](const auto &item) {\n>>>>>>     \t\t\t\t       return *this == item.first;\n>>>>>> @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n>>>>>>     \n>>>>>>     \t/* Assemble a name made of the constituent fields. */\n>>>>>>     \n>>>>>> -\tstatic const std::map<Primaries, std::string> primariesNames = {\n>>>>>> -\t\t{ Primaries::Raw, \"RAW\" },\n>>>>>> -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n>>>>>> -\t\t{ Primaries::Rec709, \"Rec709\" },\n>>>>>> -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n>>>>>> -\t};\n>>>>>> -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n>>>>>> -\t\t{ TransferFunction::Linear, \"Linear\" },\n>>>>>> -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n>>>>>> -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n>>>>>> -\t};\n>>>>>> -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n>>>>>> -\t\t{ YcbcrEncoding::None, \"None\" },\n>>>>>> -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n>>>>>> -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n>>>>>> -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n>>>>>> -\t};\n>>>>>> -\tstatic const std::map<Range, std::string> rangeNames = {\n>>>>>> -\t\t{ Range::Full, \"Full\" },\n>>>>>> -\t\t{ Range::Limited, \"Limited\" },\n>>>>>> -\t};\n>>>>>> -\n>>>>>>     \tauto itPrimaries = primariesNames.find(primaries);\n>>>>>>     \tstd::string primariesName =\n>>>>>>     \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n>>>>>> @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n>>>>>>     \treturn colorSpace->toString();\n>>>>>>     }\n>>>>>>     \n>>>>>> +/**\n>>>>>> + * \\brief Construct a color space from a string\n>>>>>> + * \\param[in] str The string\n>>>>>> + *\n>>>>>> + * The string \\a str can contain the name of a well-known color space, or be\n>>>>>> + * made of the four color space components separate by a '/' character. Any\n>>>>>> + * failure to parse the string, either because it doesn't match the expected\n>>>>>> + * format, or because the one of the names isn't recognized, will cause this\n>>>>>> + * function to return std::nullopt.\n>>>>>> + *\n>>>>>> + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n>>>>>> + * string doesn't describe a known color space\n>>>>>> + */\n>>>>>> +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n>>>>>> +{\n>>>>>> +\t/* First search for a standard color space name match. */\n>>>>>> +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n>>>>>> +\t\t\t\t\t [&str](const auto &item) {\n>>>>>> +\t\t\t\t\t\t return str == item.second;\n>>>>>> +\t\t\t\t\t });\n>>>>>> +\tif (itColorSpace != colorSpaceNames.end())\n>>>>>> +\t\treturn itColorSpace->first;\n>>>>>> +\n>>>>>> +\t/*\n>>>>>> +\t * If not found, the string must contain the four color space\n>>>>>> +\t * components separated by a '/' character.\n>>>>>> +\t */\n>>>>>> +\tconst auto &split = utils::split(str, \"/\");\n>>>>>> +\tstd::vector<std::string> components{ split.begin(), split.end() };\n>>>>>> +\n>>>>>> +\tif (components.size() != 4)\n>>>>>> +\t\treturn std::nullopt;\n>>>>>> +\n>>>>>> +\tColorSpace colorSpace = ColorSpace::Raw;\n>>>>>> +\n>>>>>> +\t/* Color primaries */\n>>>>>> +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n>>>>>> +\t\t\t\t\t[&components](const auto &item) {\n>>>>>> +\t\t\t\t\t\treturn components[0] == item.second;\n>>>>>> +\t\t\t\t\t});\n>>>>>> +\tif (itPrimaries == primariesNames.end())\n>>>>>> +\t\treturn std::nullopt;\n>>>>>> +\n>>>>>> +\tcolorSpace.primaries = itPrimaries->first;\n>>>>>> +\n>>>>>> +\t/* Transfer function */\n>>>>>> +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n>>>>>> +\t\t\t\t       [&components](const auto &item) {\n>>>>>> +\t\t\t\t\t       return components[1] == item.second;\n>>>>>> +\t\t\t\t       });\n>>>>>> +\tif (itTransfer == transferNames.end())\n>>>>>> +\t\treturn std::nullopt;\n>>>>>> +\n>>>>>> +\tcolorSpace.transferFunction = itTransfer->first;\n>>>>>> +\n>>>>>> +\t/* YCbCr encoding */\n>>>>>> +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n>>>>>> +\t\t\t\t       [&components](const auto &item) {\n>>>>>> +\t\t\t\t\t       return components[2] == item.second;\n>>>>>> +\t\t\t\t       });\n>>>>>> +\tif (itEncoding == encodingNames.end())\n>>>>>> +\t\treturn std::nullopt;\n>>>>>> +\n>>>>>> +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n>>>>>> +\n>>>>>> +\t/* Quantization range */\n>>>>>> +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n>>>>>> +\t\t\t\t    [&components](const auto &item) {\n>>>>>> +\t\t\t\t\t    return components[3] == item.second;\n>>>>>> +\t\t\t\t    });\n>>>>>> +\tif (itRange == rangeNames.end())\n>>>>>> +\t\treturn std::nullopt;\n>>>>>> +\n>>>>>> +\tcolorSpace.range = itRange->first;\n>>>>>> +\n>>>>>> +\treturn colorSpace;\n>>>>>> +}\n>>>>>> +\n>>>>>>     /**\n>>>>>>      * \\brief Compare color spaces for equality\n>>>>>>      * \\return True if the two color spaces are identical, false otherwise","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 72A71C3272\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 25 Aug 2022 15:43:11 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CBB6261FBA;\n\tThu, 25 Aug 2022 17:43:10 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 62F3661FA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 25 Aug 2022 17:43:09 +0200 (CEST)","from [IPV6:2401:4900:1f3f:806e:6647:8e5c:f441:ca9a] (unknown\n\t[IPv6:2401:4900:1f3f:806e:6647:8e5c:f441:ca9a])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 451472B3;\n\tThu, 25 Aug 2022 17:43:07 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661442190;\n\tbh=DOuKicP8eWNWgGxX/Kpag8xFrqsXTzDiJBuVSpGjk10=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=debv7uXnxH2HEbSoT/8OnseXCegpmPQor6ta07E1Ds8uLPMBtLnwn8Zk4XgNXH/Qm\n\tDsS0/NIm1190XIUM6mfYd73ci44WyblQyo7D2FnVmUvK3aBmWpzQ/c7bzN1TkD4NDD\n\t5psxuasoLVWa7GoBUjUlshyjTVYcX7aB3HkSlc1v3ZU2y08yc1ehM0Xd1y1o5wX3Yl\n\tpjwaYOG5lvn3ZE0YlfymmMrt3ybmJ8vBKKRbdU097ZTGv9UKD0+VUOX3w8rAbWJGFI\n\t5iAsDINJOuAS6W9rF1sqPWKrDZ4gtxpAx39ijeEhQYcjRThxFeIqe6sO9PR3idaqey\n\twKruQvcVPEbQA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661442188;\n\tbh=DOuKicP8eWNWgGxX/Kpag8xFrqsXTzDiJBuVSpGjk10=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=j9QPn0P0506rPfJAZnHj7bqQ82BXKfpZyptyLERSaPx4o82dijCq0yOKI8ig/KxzT\n\tu2lQcBT3Qj0PacwW1fDrxzD2Wcn2dCiKYs2VbQZ++YSntildBJn40fW4E7y0bLDCHo\n\tpigpAb7pR3MPqHgRfW8eSZul7tggH7GYwmbGAr94="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"j9QPn0P0\"; dkim-atps=neutral","Message-ID":"<75f43528-901e-841b-6411-e549e0749be9@ideasonboard.com>","Date":"Thu, 25 Aug 2022 21:13:02 +0530","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101\n\tThunderbird/91.12.0","Content-Language":"en-US","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>\n\t<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>\n\t<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>\n\t<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>\n\t<ae8213b5-2b9e-4225-c75e-921f2e7825b6@ideasonboard.com>\n\t<YweJBuv95NHOX3Qi@pendragon.ideasonboard.com>","In-Reply-To":"<YweJBuv95NHOX3Qi@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Umang Jain via libcamera-devel <libcamera-devel@lists.libcamera.org>","Reply-To":"Umang Jain <umang.jain@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":24773,"web_url":"https://patchwork.libcamera.org/comment/24773/","msgid":"<YweanQJRb4p3ZYfj@pendragon.ideasonboard.com>","date":"2022-08-25T15:51:57","subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Thu, Aug 25, 2022 at 09:13:02PM +0530, Umang Jain wrote:\n> On 8/25/22 8:06 PM, Laurent Pinchart wrote:\n> > On Thu, Aug 25, 2022 at 06:49:53PM +0530, Umang Jain wrote:\n> >> On 8/25/22 3:02 AM, Laurent Pinchart wrote:\n> >>> On Wed, Aug 24, 2022 at 12:40:59PM +0300, Laurent Pinchart via libcamera-devel wrote:\n> >>>> On Wed, Aug 24, 2022 at 12:07:59PM +0530, Umang Jain wrote:\n> >>>>> On 8/23/22 11:13 PM, Laurent Pinchart via libcamera-devel wrote:\n> >>>>>> Add a ColorSpace:fromString() function to parse a string into a color\n> >>>>>> space. The string can either contain the name of a well-known color\n> >>>>>> space, or four color space components separate by a '/' character.\n> >>>>> \n> >>>>> I don't see the order of four components separated by '/' - documented\n> >>>>> in the codebase.\n> >>>>> Should we document the string order as well?\n> >>>>>\n> >>>>> '''\n> >>>>> The string representation of the colorspace separated by '/' is as follows:\n> >>>>>        <Color primaries>/<Transfer function>/<Y'CbCr Encoding>/<Range>\n> >>>>> '''\n> >>>> \n> >>>> I'll expand the documentation of the function to make this more\n> >>>> explicit.\n> >> \n> >> Thank you!\n> >>\n> >>>> I'm also wondering (warning, bikeshedding ahead) if the '/'-separated\n> >>>> format is the best option. GStreamer uses colons to separate the\n> >>>> components, and only accepts numerical values for the components in that\n> >>>> case. I'm not aware of (but haven't looked for) alternatives.\n> >> \n> >> Oh, so we can't really align with gstreamer using the colon(':') because\n> >> it would split awkwardly with utils::split(str, \":\")  I think\n> >>\n> >> ColorSpace::Primaries::Rec709:ColorSpace::TransferFunction::Rec709:ColorSpace::YcbcrEncoding::Rec709:ColorSpace::Range::Full\n> > \n> > The string doesn't have to fully qualify the components, it would be\n> >\n> > \tRec709:Rec709:Rec709:Full\n> \n> Yes correct, it can be - Can we keep \":\" as the splitter then?  ;-)\n\nShould I then update toString() too ?\n\nDavid, any opinion ?\n\n> >> In that case, I think \"/\" is our best choice. Second best I think will\n> >> be \"|\"\n> >>\n> >> I saw a few Colorspace::toString() randomly on the internet, but none\n> >> were structural. They were mostly just meant to print it out for logs\n> >> (and not treating as string input).\n> >>\n> >> I also saw DRM also has colorspaces but haven't came across a helper\n> >> like we need. I am not sure if it's worth to look further! \"/\" is\n> >> already a good starting point, given our requirements.\n> >>\n> >>> By the way, the '/'-separated format comes from toString(). If we want\n> >>> to change it, we should update the toString() function as well.\n> >> \n> >> Ack.\n> >>\n> >>>>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >>>>> Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>\n> >>>>>\n> >>>>>> ---\n> >>>>>>     include/libcamera/color_space.h |   2 +\n> >>>>>>     src/libcamera/color_space.cpp   | 149 +++++++++++++++++++++++++-------\n> >>>>>>     2 files changed, 121 insertions(+), 30 deletions(-)\n> >>>>>>\n> >>>>>> diff --git a/include/libcamera/color_space.h b/include/libcamera/color_space.h\n> >>>>>> index 8030a264c66f..f493f72d2db8 100644\n> >>>>>> --- a/include/libcamera/color_space.h\n> >>>>>> +++ b/include/libcamera/color_space.h\n> >>>>>> @@ -59,6 +59,8 @@ public:\n> >>>>>>     \n> >>>>>>     \tstd::string toString() const;\n> >>>>>>     \tstatic std::string toString(const std::optional<ColorSpace> &colorSpace);\n> >>>>>> +\n> >>>>>> +\tstatic std::optional<ColorSpace> fromString(const std::string &str);\n> >>>>>>     };\n> >>>>>>     \n> >>>>>>     bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);\n> >>>>>> diff --git a/src/libcamera/color_space.cpp b/src/libcamera/color_space.cpp\n> >>>>>> index 1b2dd2404452..5233626f5ae9 100644\n> >>>>>> --- a/src/libcamera/color_space.cpp\n> >>>>>> +++ b/src/libcamera/color_space.cpp\n> >>>>>> @@ -12,6 +12,9 @@\n> >>>>>>     #include <map>\n> >>>>>>     #include <sstream>\n> >>>>>>     #include <utility>\n> >>>>>> +#include <vector>\n> >>>>>> +\n> >>>>>> +#include <libcamera/base/utils.h>\n> >>>>>>     \n> >>>>>>     /**\n> >>>>>>      * \\file color_space.h\n> >>>>>> @@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {\n> >>>>>>      * \\brief The pixel range used with by color space\n> >>>>>>      */\n> >>>>>>     \n> >>>>>> +namespace {\n> >>>>>> +\n> >>>>>> +const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> >>>>>> +\t{ ColorSpace::Raw, \"RAW\" },\n> >>>>>> +\t{ ColorSpace::Srgb, \"sRGB\" },\n> >>>>>> +\t{ ColorSpace::Sycc, \"sYCC\" },\n> >>>>>> +\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> >>>>>> +\t{ ColorSpace::Rec709, \"Rec709\" },\n> >>>>>> +\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> >>>>>> +} };\n> >>>>>> +\n> >>>>>> +const std::map<ColorSpace::Primaries, std::string> primariesNames = {\n> >>>>>> +\t{ ColorSpace::Primaries::Raw, \"RAW\" },\n> >>>>>> +\t{ ColorSpace::Primaries::Smpte170m, \"SMPTE170M\" },\n> >>>>>> +\t{ ColorSpace::Primaries::Rec709, \"Rec709\" },\n> >>>>>> +\t{ ColorSpace::Primaries::Rec2020, \"Rec2020\" },\n> >>>>>> +};\n> >>>>>> +\n> >>>>>> +const std::map<ColorSpace::TransferFunction, std::string> transferNames = {\n> >>>>>> +\t{ ColorSpace::TransferFunction::Linear, \"Linear\" },\n> >>>>>> +\t{ ColorSpace::TransferFunction::Srgb, \"sRGB\" },\n> >>>>>> +\t{ ColorSpace::TransferFunction::Rec709, \"Rec709\" },\n> >>>>>> +};\n> >>>>>> +\n> >>>>>> +const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {\n> >>>>>> +\t{ ColorSpace::YcbcrEncoding::None, \"None\" },\n> >>>>>> +\t{ ColorSpace::YcbcrEncoding::Rec601, \"Rec601\" },\n> >>>>>> +\t{ ColorSpace::YcbcrEncoding::Rec709, \"Rec709\" },\n> >>>>>> +\t{ ColorSpace::YcbcrEncoding::Rec2020, \"Rec2020\" },\n> >>>>>> +};\n> >>>>>> +\n> >>>>>> +const std::map<ColorSpace::Range, std::string> rangeNames = {\n> >>>>>> +\t{ ColorSpace::Range::Full, \"Full\" },\n> >>>>>> +\t{ ColorSpace::Range::Limited, \"Limited\" },\n> >>>>>> +};\n> >>>>>> +\n> >>>>>> +} /* namespace */\n> >>>>>> +\n> >>>>>>     /**\n> >>>>>>      * \\brief Assemble and return a readable string representation of the\n> >>>>>>      * ColorSpace\n> >>>>>> @@ -223,14 +264,6 @@ std::string ColorSpace::toString() const\n> >>>>>>     {\n> >>>>>>     \t/* Print out a brief name only for standard color spaces. */\n> >>>>>>     \n> >>>>>> -\tstatic const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {\n> >>>>>> -\t\t{ ColorSpace::Raw, \"RAW\" },\n> >>>>>> -\t\t{ ColorSpace::Srgb, \"sRGB\" },\n> >>>>>> -\t\t{ ColorSpace::Sycc, \"sYCC\" },\n> >>>>>> -\t\t{ ColorSpace::Smpte170m, \"SMPTE170M\" },\n> >>>>>> -\t\t{ ColorSpace::Rec709, \"Rec709\" },\n> >>>>>> -\t\t{ ColorSpace::Rec2020, \"Rec2020\" },\n> >>>>>> -\t} };\n> >>>>>>     \tauto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> >>>>>>     \t\t\t       [this](const auto &item) {\n> >>>>>>     \t\t\t\t       return *this == item.first;\n> >>>>>> @@ -240,28 +273,6 @@ std::string ColorSpace::toString() const\n> >>>>>>     \n> >>>>>>     \t/* Assemble a name made of the constituent fields. */\n> >>>>>>     \n> >>>>>> -\tstatic const std::map<Primaries, std::string> primariesNames = {\n> >>>>>> -\t\t{ Primaries::Raw, \"RAW\" },\n> >>>>>> -\t\t{ Primaries::Smpte170m, \"SMPTE170M\" },\n> >>>>>> -\t\t{ Primaries::Rec709, \"Rec709\" },\n> >>>>>> -\t\t{ Primaries::Rec2020, \"Rec2020\" },\n> >>>>>> -\t};\n> >>>>>> -\tstatic const std::map<TransferFunction, std::string> transferNames = {\n> >>>>>> -\t\t{ TransferFunction::Linear, \"Linear\" },\n> >>>>>> -\t\t{ TransferFunction::Srgb, \"sRGB\" },\n> >>>>>> -\t\t{ TransferFunction::Rec709, \"Rec709\" },\n> >>>>>> -\t};\n> >>>>>> -\tstatic const std::map<YcbcrEncoding, std::string> encodingNames = {\n> >>>>>> -\t\t{ YcbcrEncoding::None, \"None\" },\n> >>>>>> -\t\t{ YcbcrEncoding::Rec601, \"Rec601\" },\n> >>>>>> -\t\t{ YcbcrEncoding::Rec709, \"Rec709\" },\n> >>>>>> -\t\t{ YcbcrEncoding::Rec2020, \"Rec2020\" },\n> >>>>>> -\t};\n> >>>>>> -\tstatic const std::map<Range, std::string> rangeNames = {\n> >>>>>> -\t\t{ Range::Full, \"Full\" },\n> >>>>>> -\t\t{ Range::Limited, \"Limited\" },\n> >>>>>> -\t};\n> >>>>>> -\n> >>>>>>     \tauto itPrimaries = primariesNames.find(primaries);\n> >>>>>>     \tstd::string primariesName =\n> >>>>>>     \t\titPrimaries == primariesNames.end() ? \"Invalid\" : itPrimaries->second;\n> >>>>>> @@ -303,6 +314,84 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)\n> >>>>>>     \treturn colorSpace->toString();\n> >>>>>>     }\n> >>>>>>     \n> >>>>>> +/**\n> >>>>>> + * \\brief Construct a color space from a string\n> >>>>>> + * \\param[in] str The string\n> >>>>>> + *\n> >>>>>> + * The string \\a str can contain the name of a well-known color space, or be\n> >>>>>> + * made of the four color space components separate by a '/' character. Any\n> >>>>>> + * failure to parse the string, either because it doesn't match the expected\n> >>>>>> + * format, or because the one of the names isn't recognized, will cause this\n> >>>>>> + * function to return std::nullopt.\n> >>>>>> + *\n> >>>>>> + * \\return The ColorSpace corresponding to the string, or std::nullopt if the\n> >>>>>> + * string doesn't describe a known color space\n> >>>>>> + */\n> >>>>>> +std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)\n> >>>>>> +{\n> >>>>>> +\t/* First search for a standard color space name match. */\n> >>>>>> +\tauto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),\n> >>>>>> +\t\t\t\t\t [&str](const auto &item) {\n> >>>>>> +\t\t\t\t\t\t return str == item.second;\n> >>>>>> +\t\t\t\t\t });\n> >>>>>> +\tif (itColorSpace != colorSpaceNames.end())\n> >>>>>> +\t\treturn itColorSpace->first;\n> >>>>>> +\n> >>>>>> +\t/*\n> >>>>>> +\t * If not found, the string must contain the four color space\n> >>>>>> +\t * components separated by a '/' character.\n> >>>>>> +\t */\n> >>>>>> +\tconst auto &split = utils::split(str, \"/\");\n> >>>>>> +\tstd::vector<std::string> components{ split.begin(), split.end() };\n> >>>>>> +\n> >>>>>> +\tif (components.size() != 4)\n> >>>>>> +\t\treturn std::nullopt;\n> >>>>>> +\n> >>>>>> +\tColorSpace colorSpace = ColorSpace::Raw;\n> >>>>>> +\n> >>>>>> +\t/* Color primaries */\n> >>>>>> +\tauto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),\n> >>>>>> +\t\t\t\t\t[&components](const auto &item) {\n> >>>>>> +\t\t\t\t\t\treturn components[0] == item.second;\n> >>>>>> +\t\t\t\t\t});\n> >>>>>> +\tif (itPrimaries == primariesNames.end())\n> >>>>>> +\t\treturn std::nullopt;\n> >>>>>> +\n> >>>>>> +\tcolorSpace.primaries = itPrimaries->first;\n> >>>>>> +\n> >>>>>> +\t/* Transfer function */\n> >>>>>> +\tauto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),\n> >>>>>> +\t\t\t\t       [&components](const auto &item) {\n> >>>>>> +\t\t\t\t\t       return components[1] == item.second;\n> >>>>>> +\t\t\t\t       });\n> >>>>>> +\tif (itTransfer == transferNames.end())\n> >>>>>> +\t\treturn std::nullopt;\n> >>>>>> +\n> >>>>>> +\tcolorSpace.transferFunction = itTransfer->first;\n> >>>>>> +\n> >>>>>> +\t/* YCbCr encoding */\n> >>>>>> +\tauto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),\n> >>>>>> +\t\t\t\t       [&components](const auto &item) {\n> >>>>>> +\t\t\t\t\t       return components[2] == item.second;\n> >>>>>> +\t\t\t\t       });\n> >>>>>> +\tif (itEncoding == encodingNames.end())\n> >>>>>> +\t\treturn std::nullopt;\n> >>>>>> +\n> >>>>>> +\tcolorSpace.ycbcrEncoding = itEncoding->first;\n> >>>>>> +\n> >>>>>> +\t/* Quantization range */\n> >>>>>> +\tauto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),\n> >>>>>> +\t\t\t\t    [&components](const auto &item) {\n> >>>>>> +\t\t\t\t\t    return components[3] == item.second;\n> >>>>>> +\t\t\t\t    });\n> >>>>>> +\tif (itRange == rangeNames.end())\n> >>>>>> +\t\treturn std::nullopt;\n> >>>>>> +\n> >>>>>> +\tcolorSpace.range = itRange->first;\n> >>>>>> +\n> >>>>>> +\treturn colorSpace;\n> >>>>>> +}\n> >>>>>> +\n> >>>>>>     /**\n> >>>>>>      * \\brief Compare color spaces for equality\n> >>>>>>      * \\return True if the two color spaces are identical, false otherwise\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8AA48C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 25 Aug 2022 15:52:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DB25061FBF;\n\tThu, 25 Aug 2022 17:52:05 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 792D861FA0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 25 Aug 2022 17:52:04 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id BE9D22B3;\n\tThu, 25 Aug 2022 17:52:03 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1661442725;\n\tbh=bREZ/+RZ6d3jBWvtqk73IQeeIUkMV7NmRI5UKALxP1Q=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=btc481v/SrL7KcUvVBdr44f+hOHFaOxitQw83LYr36vOwOz2Lwe7FjsasQR/oeZF5\n\tvf1bPgBBFOVym7SktVQ4Ba/xYQfS7xu9BoPRF4KolzHW7Kv23smfXqQ9mLhCtX31gt\n\tT7kwdhavE+BmC6bV66bNvnES5ZQTOaIOkhmXTSlscibEgA4MLkp7+l/P340Seu6U5z\n\t4xs4C9t9VdbjCf2+E1u/TbtsZXx6Q8I/ZVVTi3lb+R3Ob1PcI60sqk21Nw2AGak6YF\n\t1lPxq3HLaT1DxZ+sbz71I3F5QFCmH3sj04ZjRUOeJpzniHNx+pimwxHN2hvf0bAzFJ\n\th0YFjmn8wQALg==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1661442724;\n\tbh=bREZ/+RZ6d3jBWvtqk73IQeeIUkMV7NmRI5UKALxP1Q=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=d/EUz7sOBDntb9D04eRbLcjqrWv+/kDB9Cifsj+U4tvcU+Jvcc8rClVfcnpJh8MPh\n\t97erF4jl4Yk+fx8W70L5pM60lB22NgbzQB7CiuZKOsBy253R1esNeSIiPHPNQsIYMn\n\tOOi/mJBeyWfCOt/8bKQYay5lzTSUZsqBR1X5+Tt8="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"d/EUz7sO\"; dkim-atps=neutral","Date":"Thu, 25 Aug 2022 18:51:57 +0300","To":"Umang Jain <umang.jain@ideasonboard.com>","Message-ID":"<YweanQJRb4p3ZYfj@pendragon.ideasonboard.com>","References":"<20220823174314.14881-1-laurent.pinchart@ideasonboard.com>\n\t<20220823174314.14881-4-laurent.pinchart@ideasonboard.com>\n\t<1a49217a-2b6b-e8cf-c6b0-3bf7c1c6bd25@ideasonboard.com>\n\t<YwXyK3NnOq1Fcfif@pendragon.ideasonboard.com>\n\t<YwaY4nwND7DhtJJY@pendragon.ideasonboard.com>\n\t<ae8213b5-2b9e-4225-c75e-921f2e7825b6@ideasonboard.com>\n\t<YweJBuv95NHOX3Qi@pendragon.ideasonboard.com>\n\t<75f43528-901e-841b-6411-e549e0749be9@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<75f43528-901e-841b-6411-e549e0749be9@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH 3/6] libcamera: color_space: Add\n\tfromString() function","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","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>","From":"Laurent Pinchart via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]