[{"id":23810,"web_url":"https://patchwork.libcamera.org/comment/23810/","msgid":"<YstRj3JO/9WOoJkA@pendragon.ideasonboard.com>","date":"2022-07-10T22:24:15","subject":"Re: [libcamera-devel] [PATCH v10 1/2] libcamera: controls: Use\n\tstd::optional to handle invalid control values","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Christian,\n\nThank you for the patch.\n\nOn Tue, Jul 05, 2022 at 10:55:48AM +0100, Christian Rauch wrote:\n> Previously, ControlList::get<T>() would use default constructed objects to\n> indicate that a ControlList does not have the requested Control. This has\n> several disadvantages: 1) It requires types to be default constructible,\n> 2) it does not differentiate between a default constructed object and an\n> object that happens to have the same state as a default constructed object.\n> \n> std::optional<T> additionally stores the information if the object is valid\n> or not, and therefore is more expressive than a default constructed object.\n\nThere are a few changes I'd like to make, but to avoid further delays,\nthey can go on top. I'll send them as separate patches and CC you.\nDepending on the review timing we can merge them all together, or merge\nthis patch first (once it goes through the integration tests, as it\ntouches the Android HAL I want to run the Android camera CTS).\n\n> Signed-off-by: Christian Rauch <Rauch.Christian@gmx.de>\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  include/libcamera/controls.h                  |  5 +++--\n>  src/android/camera_capabilities.cpp           | 12 +++++-----\n>  src/android/camera_device.cpp                 | 21 +++++++++---------\n>  src/android/camera_hal_manager.cpp            |  2 +-\n>  src/cam/main.cpp                              |  4 ++--\n>  src/gstreamer/gstlibcamerasrc.cpp             |  2 +-\n>  src/ipa/raspberrypi/raspberrypi.cpp           |  2 +-\n>  src/libcamera/pipeline/ipu3/ipu3.cpp          |  9 ++++----\n>  .../pipeline/raspberrypi/raspberrypi.cpp      |  9 ++++----\n>  src/qcam/dng_writer.cpp                       | 22 +++++++++----------\n>  10 files changed, 44 insertions(+), 44 deletions(-)\n> \n> diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h\n> index 665bcac1..192be784 100644\n> --- a/include/libcamera/controls.h\n> +++ b/include/libcamera/controls.h\n> @@ -8,6 +8,7 @@\n>  #pragma once\n> \n>  #include <assert.h>\n> +#include <optional>\n>  #include <set>\n>  #include <stdint.h>\n>  #include <string>\n> @@ -373,11 +374,11 @@ public:\n>  \tbool contains(unsigned int id) const;\n> \n>  \ttemplate<typename T>\n> -\tT get(const Control<T> &ctrl) const\n> +\tstd::optional<T> get(const Control<T> &ctrl) const\n>  \t{\n>  \t\tconst ControlValue *val = find(ctrl.id());\n>  \t\tif (!val)\n> -\t\t\treturn T{};\n> +\t\t\treturn std::nullopt;\n> \n>  \t\treturn val->get<T>();\n>  \t}\n> diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp\n> index 6f197eb8..5304b2da 100644\n> --- a/src/android/camera_capabilities.cpp\n> +++ b/src/android/camera_capabilities.cpp\n> @@ -1042,7 +1042,7 @@ int CameraCapabilities::initializeStaticMetadata()\n>  \t/* Sensor static metadata. */\n>  \tstd::array<int32_t, 2> pixelArraySize;\n>  \t{\n> -\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> +\t\tconst Size &size = properties.get(properties::PixelArraySize).value_or(Size{});\n>  \t\tpixelArraySize[0] = size.width;\n>  \t\tpixelArraySize[1] = size.height;\n>  \t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> @@ -1050,10 +1050,10 @@ int CameraCapabilities::initializeStaticMetadata()\n>  \t}\n> \n>  \tif (properties.contains(properties::UnitCellSize)) {\n> -\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> +\t\tconst auto &cellSize = properties.get<Size>(properties::UnitCellSize);\n>  \t\tstd::array<float, 2> physicalSize{\n> -\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> -\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> +\t\t\tcellSize->width * pixelArraySize[0] / 1e6f,\n> +\t\t\tcellSize->height * pixelArraySize[1] / 1e6f\n>  \t\t};\n>  \t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n>  \t\t\t\t\t  physicalSize);\n> @@ -1061,7 +1061,7 @@ int CameraCapabilities::initializeStaticMetadata()\n> \n>  \t{\n>  \t\tconst Span<const Rectangle> &rects =\n> -\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> +\t\t\tproperties.get(properties::PixelArrayActiveAreas).value_or(Span<const Rectangle>{});\n>  \t\tstd::vector<int32_t> data{\n>  \t\t\tstatic_cast<int32_t>(rects[0].x),\n>  \t\t\tstatic_cast<int32_t>(rects[0].y),\n> @@ -1080,7 +1080,7 @@ int CameraCapabilities::initializeStaticMetadata()\n> \n>  \t/* Report the color filter arrangement if the camera reports it. */\n>  \tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> -\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> +\t\tuint8_t filterArr = *properties.get(properties::draft::ColorFilterArrangement);\n>  \t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n>  \t\t\t\t\t  filterArr);\n>  \t}\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index 8c039fb9..46621232 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -306,7 +306,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n>  \tconst ControlList &properties = camera_->properties();\n> \n>  \tif (properties.contains(properties::Location)) {\n> -\t\tint32_t location = properties.get(properties::Location);\n> +\t\tint32_t location = *properties.get(properties::Location);\n>  \t\tswitch (location) {\n>  \t\tcase properties::CameraLocationFront:\n>  \t\t\tfacing_ = CAMERA_FACING_FRONT;\n> @@ -356,7 +356,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n>  \t * metadata.\n>  \t */\n>  \tif (properties.contains(properties::Rotation)) {\n> -\t\tint rotation = properties.get(properties::Rotation);\n> +\t\tint rotation = *properties.get(properties::Rotation);\n>  \t\torientation_ = (360 - rotation) % 360;\n>  \t\tif (cameraConfigData && cameraConfigData->rotation != -1 &&\n>  \t\t    orientation_ != cameraConfigData->rotation) {\n> @@ -1181,7 +1181,8 @@ void CameraDevice::requestComplete(Request *request)\n>  \t * as soon as possible, earlier than request completion time.\n>  \t */\n>  \tuint64_t sensorTimestamp = static_cast<uint64_t>(request->metadata()\n> -\t\t\t\t\t\t\t .get(controls::SensorTimestamp));\n> +\t\t\t\t\t\t\t\t .get(controls::SensorTimestamp)\n> +\t\t\t\t\t\t\t\t .value_or(0));\n>  \tnotifyShutter(descriptor->frameNumber_, sensorTimestamp);\n> \n>  \tLOG(HAL, Debug) << \"Request \" << request->cookie() << \" completed with \"\n> @@ -1560,29 +1561,28 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons\n>  \t\t\t\t rolling_shutter_skew);\n> \n>  \t/* Add metadata tags reported by libcamera. */\n> -\tconst int64_t timestamp = metadata.get(controls::SensorTimestamp);\n> +\tconst int64_t timestamp = metadata.get(controls::SensorTimestamp).value_or(0);\n>  \tresultMetadata->addEntry(ANDROID_SENSOR_TIMESTAMP, timestamp);\n> \n>  \tif (metadata.contains(controls::draft::PipelineDepth)) {\n> -\t\tuint8_t pipeline_depth =\n> -\t\t\tmetadata.get<int32_t>(controls::draft::PipelineDepth);\n> +\t\tuint8_t pipeline_depth = *metadata.get<int32_t>(controls::draft::PipelineDepth);\n>  \t\tresultMetadata->addEntry(ANDROID_REQUEST_PIPELINE_DEPTH,\n>  \t\t\t\t\t pipeline_depth);\n>  \t}\n> \n>  \tif (metadata.contains(controls::ExposureTime)) {\n> -\t\tint64_t exposure = metadata.get(controls::ExposureTime) * 1000ULL;\n> +\t\tint64_t exposure = *metadata.get(controls::ExposureTime) * 1000ULL;\n>  \t\tresultMetadata->addEntry(ANDROID_SENSOR_EXPOSURE_TIME, exposure);\n>  \t}\n> \n>  \tif (metadata.contains(controls::FrameDuration)) {\n> -\t\tint64_t duration = metadata.get(controls::FrameDuration) * 1000;\n> +\t\tint64_t duration = *metadata.get(controls::FrameDuration) * 1000;\n>  \t\tresultMetadata->addEntry(ANDROID_SENSOR_FRAME_DURATION,\n>  \t\t\t\t\t duration);\n>  \t}\n> \n>  \tif (metadata.contains(controls::ScalerCrop)) {\n> -\t\tRectangle crop = metadata.get(controls::ScalerCrop);\n> +\t\tRectangle crop = *metadata.get(controls::ScalerCrop);\n>  \t\tint32_t cropRect[] = {\n>  \t\t\tcrop.x, crop.y, static_cast<int32_t>(crop.width),\n>  \t\t\tstatic_cast<int32_t>(crop.height),\n> @@ -1591,8 +1591,7 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons\n>  \t}\n> \n>  \tif (metadata.contains(controls::draft::TestPatternMode)) {\n> -\t\tconst int32_t testPatternMode =\n> -\t\t\tmetadata.get(controls::draft::TestPatternMode);\n> +\t\tconst int32_t testPatternMode = *metadata.get(controls::draft::TestPatternMode);\n>  \t\tresultMetadata->addEntry(ANDROID_SENSOR_TEST_PATTERN_MODE,\n>  \t\t\t\t\t testPatternMode);\n>  \t}\n> diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp\n> index 5f7bfe26..0bffe96f 100644\n> --- a/src/android/camera_hal_manager.cpp\n> +++ b/src/android/camera_hal_manager.cpp\n> @@ -232,7 +232,7 @@ int32_t CameraHalManager::cameraLocation(const Camera *cam)\n>  \tif (!properties.contains(properties::Location))\n>  \t\treturn -1;\n> \n> -\treturn properties.get(properties::Location);\n> +\treturn *properties.get(properties::Location);\n>  }\n> \n>  CameraDevice *CameraHalManager::cameraDeviceFromHalId(unsigned int id)\n> diff --git a/src/cam/main.cpp b/src/cam/main.cpp\n> index 79875ed7..d8115cd8 100644\n> --- a/src/cam/main.cpp\n> +++ b/src/cam/main.cpp\n> @@ -301,7 +301,7 @@ std::string CamApp::cameraName(const Camera *camera)\n>  \t * is only used if the location isn't present or is set to External.\n>  \t */\n>  \tif (props.contains(properties::Location)) {\n> -\t\tswitch (props.get(properties::Location)) {\n> +\t\tswitch (*props.get(properties::Location)) {\n>  \t\tcase properties::CameraLocationFront:\n>  \t\t\taddModel = false;\n>  \t\t\tname = \"Internal front camera \";\n> @@ -321,7 +321,7 @@ std::string CamApp::cameraName(const Camera *camera)\n>  \t\t * If the camera location is not availble use the camera model\n>  \t\t * to build the camera name.\n>  \t\t */\n> -\t\tname = \"'\" + props.get(properties::Model) + \"' \";\n> +\t\tname = \"'\" + *props.get(properties::Model) + \"' \";\n>  \t}\n> \n>  \tname += \"(\" + camera->id() + \")\";\n> diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp\n> index a7a0c440..3d3efc0c 100644\n> --- a/src/gstreamer/gstlibcamerasrc.cpp\n> +++ b/src/gstreamer/gstlibcamerasrc.cpp\n> @@ -234,7 +234,7 @@ GstLibcameraSrcState::requestCompleted(Request *request)\n>  \t}\n> \n>  \tif (GST_ELEMENT_CLOCK(src_)) {\n> -\t\tint64_t timestamp = request->metadata().get(controls::SensorTimestamp);\n> +\t\tint64_t timestamp = request->metadata().get(controls::SensorTimestamp).value_or(0);\n> \n>  \t\tGstClockTime gst_base_time = GST_ELEMENT(src_)->base_time;\n>  \t\tGstClockTime gst_now = gst_clock_get_time(GST_ELEMENT_CLOCK(src_));\n> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\n> index f8d37b87..c7492a77 100644\n> --- a/src/ipa/raspberrypi/raspberrypi.cpp\n> +++ b/src/ipa/raspberrypi/raspberrypi.cpp\n> @@ -993,7 +993,7 @@ void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)\n> \n>  void IPARPi::prepareISP(const ISPConfig &data)\n>  {\n> -\tint64_t frameTimestamp = data.controls.get(controls::SensorTimestamp);\n> +\tint64_t frameTimestamp = data.controls.get(controls::SensorTimestamp).value_or(0);\n>  \tRPiController::Metadata lastMetadata;\n>  \tSpan<uint8_t> embeddedBuffer;\n> \n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index b7dda282..43db7b68 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -1145,7 +1145,7 @@ int PipelineHandlerIPU3::registerCameras()\n>  \t\t/* Convert the sensor rotation to a transformation */\n>  \t\tint32_t rotation = 0;\n>  \t\tif (data->properties_.contains(properties::Rotation))\n> -\t\t\trotation = data->properties_.get(properties::Rotation);\n> +\t\t\trotation = *(data->properties_.get(properties::Rotation));\n>  \t\telse\n>  \t\t\tLOG(IPU3, Warning) << \"Rotation control not exposed by \"\n>  \t\t\t\t\t   << cio2->sensor()->id()\n> @@ -1331,7 +1331,7 @@ void IPU3CameraData::imguOutputBufferReady(FrameBuffer *buffer)\n>  \trequest->metadata().set(controls::draft::PipelineDepth, 3);\n>  \t/* \\todo Actually apply the scaler crop region to the ImgU. */\n>  \tif (request->controls().contains(controls::ScalerCrop))\n> -\t\tcropRegion_ = request->controls().get(controls::ScalerCrop);\n> +\t\tcropRegion_ = *(request->controls().get(controls::ScalerCrop));\n>  \trequest->metadata().set(controls::ScalerCrop, cropRegion_);\n> \n>  \tif (frameInfos_.tryComplete(info))\n> @@ -1424,7 +1424,7 @@ void IPU3CameraData::statBufferReady(FrameBuffer *buffer)\n>  \t\treturn;\n>  \t}\n> \n> -\tipa_->processStatsBuffer(info->id, request->metadata().get(controls::SensorTimestamp),\n> +\tipa_->processStatsBuffer(info->id, request->metadata().get(controls::SensorTimestamp).value_or(0),\n>  \t\t\t\t info->statBuffer->cookie(), info->effectiveSensorControls);\n>  }\n> \n> @@ -1458,8 +1458,7 @@ void IPU3CameraData::frameStart(uint32_t sequence)\n>  \tif (!request->controls().contains(controls::draft::TestPatternMode))\n>  \t\treturn;\n> \n> -\tconst int32_t testPatternMode = request->controls().get(\n> -\t\tcontrols::draft::TestPatternMode);\n> +\tconst int32_t testPatternMode = *(request->controls().get(controls::draft::TestPatternMode));\n> \n>  \tint ret = cio2_.sensor()->setTestPatternMode(\n>  \t\tstatic_cast<controls::draft::TestPatternModeEnum>(testPatternMode));\n> diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n> index 66a84b1d..28f054cb 100644\n> --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n> +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n> @@ -364,7 +364,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n>  \t * error means the platform can never run. Let's just print a warning\n>  \t * and continue regardless; the rotation is effectively set to zero.\n>  \t */\n> -\tint32_t rotation = data_->sensor_->properties().get(properties::Rotation);\n> +\tint32_t rotation = data_->sensor_->properties().get(properties::Rotation).value_or(0);\n>  \tbool success;\n>  \tTransform rotationTransform = transformFromRotation(rotation, &success);\n>  \tif (!success)\n> @@ -1717,7 +1717,8 @@ void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &\n>  \t * V4L2_CID_NOTIFY_GAINS control (which means notifyGainsUnity_ is set).\n>  \t */\n>  \tif (notifyGainsUnity_ && controls.contains(libcamera::controls::ColourGains)) {\n> -\t\tlibcamera::Span<const float> colourGains = controls.get(libcamera::controls::ColourGains);\n> +\t\tlibcamera::Span<const float> colourGains =\n> +\t\t\t*controls.get(libcamera::controls::ColourGains);\n>  \t\t/* The control wants linear gains in the order B, Gb, Gr, R. */\n>  \t\tControlList ctrls(sensor_->controls());\n>  \t\tstd::array<int32_t, 4> gains{\n> @@ -2052,7 +2053,7 @@ Rectangle RPiCameraData::scaleIspCrop(const Rectangle &ispCrop) const\n>  void RPiCameraData::applyScalerCrop(const ControlList &controls)\n>  {\n>  \tif (controls.contains(controls::ScalerCrop)) {\n> -\t\tRectangle nativeCrop = controls.get<Rectangle>(controls::ScalerCrop);\n> +\t\tRectangle nativeCrop = *controls.get<Rectangle>(controls::ScalerCrop);\n> \n>  \t\tif (!nativeCrop.width || !nativeCrop.height)\n>  \t\t\tnativeCrop = { 0, 0, 1, 1 };\n> @@ -2090,7 +2091,7 @@ void RPiCameraData::fillRequestMetadata(const ControlList &bufferControls,\n>  \t\t\t\t\tRequest *request)\n>  {\n>  \trequest->metadata().set(controls::SensorTimestamp,\n> -\t\t\t\tbufferControls.get(controls::SensorTimestamp));\n> +\t\t\t\tbufferControls.get(controls::SensorTimestamp).value_or(0));\n> \n>  \trequest->metadata().set(controls::ScalerCrop, scalerCrop_);\n>  }\n> diff --git a/src/qcam/dng_writer.cpp b/src/qcam/dng_writer.cpp\n> index 34c8df5a..4b5d8276 100644\n> --- a/src/qcam/dng_writer.cpp\n> +++ b/src/qcam/dng_writer.cpp\n> @@ -392,7 +392,7 @@ int DNGWriter::write(const char *filename, const Camera *camera,\n>  \tTIFFSetField(tif, TIFFTAG_MAKE, \"libcamera\");\n> \n>  \tif (cameraProperties.contains(properties::Model)) {\n> -\t\tstd::string model = cameraProperties.get(properties::Model);\n> +\t\tstd::string model = *cameraProperties.get(properties::Model);\n>  \t\tTIFFSetField(tif, TIFFTAG_MODEL, model.c_str());\n>  \t\t/* \\todo set TIFFTAG_UNIQUECAMERAMODEL. */\n>  \t}\n> @@ -438,16 +438,15 @@ int DNGWriter::write(const char *filename, const Camera *camera,\n>  \tconst double eps = 1e-2;\n> \n>  \tif (metadata.contains(controls::ColourGains)) {\n> -\t\tSpan<const float> const &colourGains = metadata.get(controls::ColourGains);\n> -\t\tif (colourGains[0] > eps && colourGains[1] > eps) {\n> -\t\t\twbGain = Matrix3d::diag(colourGains[0], 1, colourGains[1]);\n> -\t\t\tneutral[0] = 1.0 / colourGains[0]; /* red */\n> -\t\t\tneutral[2] = 1.0 / colourGains[1]; /* blue */\n> +\t\tconst auto &colourGains = metadata.get(controls::ColourGains);\n> +\t\tif ((*colourGains)[0] > eps && (*colourGains)[1] > eps) {\n> +\t\t\twbGain = Matrix3d::diag((*colourGains)[0], 1, (*colourGains)[1]);\n> +\t\t\tneutral[0] = 1.0 / (*colourGains)[0]; /* red */\n> +\t\t\tneutral[2] = 1.0 / (*colourGains)[1]; /* blue */\n>  \t\t}\n>  \t}\n>  \tif (metadata.contains(controls::ColourCorrectionMatrix)) {\n> -\t\tSpan<const float> const &coeffs = metadata.get(controls::ColourCorrectionMatrix);\n> -\t\tMatrix3d ccmSupplied(coeffs);\n> +\t\tMatrix3d ccmSupplied(*metadata.get(controls::ColourCorrectionMatrix));\n>  \t\tif (ccmSupplied.determinant() > eps)\n>  \t\t\tccm = ccmSupplied;\n>  \t}\n> @@ -515,7 +514,8 @@ int DNGWriter::write(const char *filename, const Camera *camera,\n>  \tuint32_t whiteLevel = (1 << info->bitsPerSample) - 1;\n> \n>  \tif (metadata.contains(controls::SensorBlackLevels)) {\n> -\t\tSpan<const int32_t> levels = metadata.get(controls::SensorBlackLevels);\n> +\t\tSpan<const int32_t> levels =\n> +\t\t\t*metadata.get(controls::SensorBlackLevels);\n> \n>  \t\t/*\n>  \t\t * The black levels control is specified in R, Gr, Gb, B order.\n> @@ -593,13 +593,13 @@ int DNGWriter::write(const char *filename, const Camera *camera,\n>  \tTIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, strTime);\n> \n>  \tif (metadata.contains(controls::AnalogueGain)) {\n> -\t\tfloat gain = metadata.get(controls::AnalogueGain);\n> +\t\tfloat gain = *metadata.get(controls::AnalogueGain);\n>  \t\tuint16_t iso = std::min(std::max(gain * 100, 0.0f), 65535.0f);\n>  \t\tTIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1, &iso);\n>  \t}\n> \n>  \tif (metadata.contains(controls::ExposureTime)) {\n> -\t\tfloat exposureTime = metadata.get(controls::ExposureTime) / 1e6;\n> +\t\tfloat exposureTime = *metadata.get(controls::ExposureTime) / 1e6;\n>  \t\tTIFFSetField(tif, EXIFTAG_EXPOSURETIME, exposureTime);\n>  \t}\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 43D12BD1F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 10 Jul 2022 22:24:46 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 5DFCA63311;\n\tMon, 11 Jul 2022 00:24:45 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F10FD60406\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 11 Jul 2022 00:24:42 +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 3287773E;\n\tMon, 11 Jul 2022 00:24:42 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1657491885;\n\tbh=it2RQwPridDPF7irH2GG03iP/lc9MAqwLc5KxpgQLuI=;\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=eXiJNR5GvOeOLlqmbYeSDn4sYsULO+/6arQDrANKTnVrcBtAiG9/05v8CBjSyk28j\n\tyCBXL2+D0M4n5IxJ6aUNkWKZIF2QRBQ79GoLFXkJlKT3RSnMdIquNLtkjCwfVJiPCe\n\th/WylKYa/rkhc0DjqE0c2dd54BwXxX4hQ+psCtpeX3MCevYsVUtp2vS6Ll+mQjqhKF\n\tnvUMt/NldxMbCNFXligR1214VaJLyERPAsPIYXKNkI8Qnw6sA9Cw/YhLZq8tnXXxoM\n\tU+Ox9MBzI2j0hvtXnZJYcTeAX6TcYm9TAWB3CmRmQB4sHeOMUKnNg1rSMXoUQBS2j7\n\t2xT6Q/KCgjRaA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1657491882;\n\tbh=it2RQwPridDPF7irH2GG03iP/lc9MAqwLc5KxpgQLuI=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=teTaq9+09YjJQfPH9aZlVtCvL/AVZOC3edA1poTAiOzvaVAlhxH/nc1fw37K3DBhC\n\tDnZbZiwrbSNtyV5c9YibMdir3Y0XOOHO9xJ9YumuSPUyxIZVF08mjGMhmRhLTkTxxu\n\tUQvPqiNov/5m22xfFAk+lHYlGJMmd+pBWG6Z+Ylc="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"teTaq9+0\"; dkim-atps=neutral","Date":"Mon, 11 Jul 2022 01:24:15 +0300","To":"Christian Rauch <Rauch.Christian@gmx.de>","Message-ID":"<YstRj3JO/9WOoJkA@pendragon.ideasonboard.com>","References":"<20220705095549.87466-1-Rauch.Christian@gmx.de>\n\t<20220705095549.87466-2-Rauch.Christian@gmx.de>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20220705095549.87466-2-Rauch.Christian@gmx.de>","Subject":"Re: [libcamera-devel] [PATCH v10 1/2] libcamera: controls: Use\n\tstd::optional to handle invalid control values","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>"}}]