[{"id":4356,"web_url":"https://patchwork.libcamera.org/comment/4356/","msgid":"<092cc1db-fcda-b605-b4f7-e8399c830db7@ideasonboard.com>","date":"2020-03-31T12:43:03","subject":"Re: [libcamera-devel] [PATCH v3 11/11] libcamera: pipeline: simple:\n\tIntegrate converter support","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/people/4/","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"content":"Hi Laurent,\n\nOn 20/03/2020 01:48, Laurent Pinchart wrote:\n> Add support for an optional format converter, supported by the\n> SimpleConverter class. If a converter is available for the pipeline, it\n> will be used to expose additional pixel formats.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n> Changes since v2:\n> \n> - Rebase on top of V4L2PixelFormat\n> - Don't crash if the device has no converter\n> ---\n>  src/libcamera/pipeline/simple/simple.cpp | 196 ++++++++++++++++++++---\n>  1 file changed, 178 insertions(+), 18 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> index 545a99fe31ca..eb7ce8322e52 100644\n> --- a/src/libcamera/pipeline/simple/simple.cpp\n> +++ b/src/libcamera/pipeline/simple/simple.cpp\n> @@ -11,6 +11,7 @@\n>  #include <list>\n>  #include <map>\n>  #include <memory>\n> +#include <queue>\n>  #include <set>\n>  #include <string>\n>  #include <string.h>\n> @@ -31,12 +32,19 @@\n>  #include \"v4l2_subdevice.h\"\n>  #include \"v4l2_videodevice.h\"\n>  \n> +#include \"converter.h\"\n> +\n>  namespace libcamera {\n>  \n>  LOG_DEFINE_CATEGORY(SimplePipeline)\n>  \n>  class SimplePipelineHandler;\n>  \n> +struct SimplePipelineInfo {\n> +\tconst char *driver;\n> +\tconst char *converter;\n> +};\n> +\n>  class SimpleCameraData : public CameraData\n>  {\n>  public:\n> @@ -79,6 +87,8 @@ public:\n>  \n>  \tconst V4L2SubdeviceFormat &sensorFormat() { return sensorFormat_; }\n>  \n> +\tbool needConversion() const { return needConversion_; }\n> +\n>  private:\n>  \t/*\n>  \t * The SimpleCameraData instance is guaranteed to be valid as long as\n> @@ -89,6 +99,7 @@ private:\n>  \tconst SimpleCameraData *data_;\n>  \n>  \tV4L2SubdeviceFormat sensorFormat_;\n> +\tbool needConversion_;\n>  };\n>  \n>  class SimplePipelineHandler : public PipelineHandler\n> @@ -111,6 +122,7 @@ public:\n>  \n>  \tV4L2VideoDevice *video() { return video_; }\n>  \tV4L2Subdevice *subdev(const MediaEntity *entity);\n> +\tSimpleConverter *converter() { return converter_; }\n>  \n>  protected:\n>  \tint queueRequestDevice(Camera *camera, Request *request) override;\n> @@ -127,11 +139,17 @@ private:\n>  \tint createCamera(MediaEntity *sensor);\n>  \n>  \tvoid bufferReady(FrameBuffer *buffer);\n> +\tvoid converterDone(FrameBuffer *input, FrameBuffer *output);\n>  \n>  \tMediaDevice *media_;\n>  \tV4L2VideoDevice *video_;\n>  \tstd::map<const MediaEntity *, V4L2Subdevice> subdevs_;\n>  \n> +\tSimpleConverter *converter_;\n> +\tbool useConverter_;\n> +\tstd::vector<std::unique_ptr<FrameBuffer>> converterBuffers_;\n> +\tstd::queue<FrameBuffer *> converterQueue_;\n> +\n>  \tCamera *activeCamera_;\n>  };\n>  \n> @@ -209,6 +227,7 @@ int SimpleCameraData::init()\n>  {\n>  \tSimplePipelineHandler *pipe = static_cast<SimplePipelineHandler *>(pipe_);\n>  \tV4L2VideoDevice *video = pipe->video();\n> +\tSimpleConverter *converter = pipe->converter();\n>  \tint ret;\n>  \n>  \t/*\n> @@ -264,7 +283,13 @@ int SimpleCameraData::init()\n>  \t\t\tconfig.pixelFormat = pixelFormat;\n>  \t\t\tconfig.size = format.size;\n>  \n> -\t\t\tformats_[pixelFormat] = config;\n> +\t\t\tif (!converter) {\n> +\t\t\t\tformats_[pixelFormat] = config;\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\n> +\t\t\tfor (PixelFormat format : converter->formats(pixelFormat))\n> +\t\t\t\tformats_[format] = config;\n>  \t\t}\n>  \t}\n>  \n> @@ -402,6 +427,8 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n>  \t\tstatus = Adjusted;\n>  \t}\n>  \n> +\tneedConversion_ = cfg.pixelFormat != pipeConfig.pixelFormat;\n> +\n>  \tcfg.bufferCount = 3;\n>  \n>  \treturn status;\n> @@ -412,13 +439,14 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n>   */\n>  \n>  SimplePipelineHandler::SimplePipelineHandler(CameraManager *manager)\n> -\t: PipelineHandler(manager), video_(nullptr)\n> +\t: PipelineHandler(manager), video_(nullptr), converter_(nullptr)\n>  {\n>  }\n>  \n>  SimplePipelineHandler::~SimplePipelineHandler()\n>  {\n>  \tdelete video_;\n> +\tdelete converter_;\n>  }\n>  \n>  CameraConfiguration *SimplePipelineHandler::generateConfiguration(Camera *camera,\n> @@ -484,22 +512,37 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)\n>  \t\treturn ret;\n>  \n>  \t/* Configure the video node. */\n> -\tV4L2PixelFormat videoFormat = video_->toV4L2PixelFormat(cfg.pixelFormat);\n> +\tV4L2PixelFormat videoFormat = video_->toV4L2PixelFormat(pipeConfig.pixelFormat);\n>  \n> -\tV4L2DeviceFormat outputFormat = {};\n> -\toutputFormat.fourcc = videoFormat;\n> -\toutputFormat.size = cfg.size;\n> +\tV4L2DeviceFormat captureFormat = {};\n> +\tcaptureFormat.fourcc = videoFormat;\n> +\tcaptureFormat.size = cfg.size;\n>  \n> -\tret = video_->setFormat(&outputFormat);\n> +\tret = video_->setFormat(&captureFormat);\n>  \tif (ret)\n>  \t\treturn ret;\n>  \n> -\tif (outputFormat.size != cfg.size || outputFormat.fourcc != videoFormat) {\n> +\tif (captureFormat.fourcc != videoFormat || captureFormat.size != cfg.size) {\n>  \t\tLOG(SimplePipeline, Error)\n>  \t\t\t<< \"Unable to configure capture in \" << cfg.toString();\n>  \t\treturn -EINVAL;\n>  \t}\n>  \n> +\t/* Configure the converter if required. */\n> +\tuseConverter_ = config->needConversion();\n> +\n> +\tif (useConverter_) {\n> +\t\tint ret = converter_->configure(pipeConfig.pixelFormat,\n> +\t\t\t\t\t\tcfg.pixelFormat, cfg.size);\n> +\t\tif (ret < 0) {\n> +\t\t\tLOG(SimplePipeline, Error)\n> +\t\t\t\t<< \"Unable to configure converter\";\n> +\t\t\treturn ret;\n> +\t\t}\n> +\n> +\t\tLOG(SimplePipeline, Debug) << \"Using format converter\";\n> +\t}\n> +\n>  \tcfg.setStream(&data->stream_);\n>  \n>  \treturn 0;\n> @@ -510,24 +553,47 @@ int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,\n>  {\n>  \tunsigned int count = stream->configuration().bufferCount;\n>  \n> -\treturn video_->exportBuffers(count, buffers);\n> +\t/*\n> +\t * Export buffers on the converter or capture video node, depending on\n> +\t * whether the converter is used or not.\n> +\t */\n> +\tif (useConverter_)\n> +\t\treturn converter_->exportBuffers(count, buffers);\n> +\telse\n> +\t\treturn video_->exportBuffers(count, buffers);\n>  }\n>  \n>  int SimplePipelineHandler::start(Camera *camera)\n>  {\n>  \tSimpleCameraData *data = cameraData(camera);\n>  \tunsigned int count = data->stream_.configuration().bufferCount;\n> +\tint ret;\n>  \n> -\tint ret = video_->importBuffers(count);\n> +\tif (useConverter_)\n> +\t\tret = video_->allocateBuffers(count, &converterBuffers_);\n> +\telse\n> +\t\tret = video_->importBuffers(count);\n>  \tif (ret < 0)\n>  \t\treturn ret;\n>  \n>  \tret = video_->streamOn();\n>  \tif (ret < 0) {\n> -\t\tvideo_->releaseBuffers();\n> +\t\tstop(camera);\n>  \t\treturn ret;\n>  \t}\n>  \n> +\tif (useConverter_) {\n> +\t\tret = converter_->start(count);\n> +\t\tif (ret < 0) {\n> +\t\t\tstop(camera);\n> +\t\t\treturn ret;\n> +\t\t}\n> +\n> +\t\t/* Queue all internal buffers for capture. */\n> +\t\tfor (std::unique_ptr<FrameBuffer> &buffer : converterBuffers_)\n> +\t\t\tvideo_->queueBuffer(buffer.get());\n> +\t}\n> +\n>  \tactiveCamera_ = camera;\n>  \n>  \treturn 0;\n> @@ -535,8 +601,13 @@ int SimplePipelineHandler::start(Camera *camera)\n>  \n>  void SimplePipelineHandler::stop(Camera *camera)\n>  {\n> +\tif (useConverter_)\n> +\t\tconverter_->stop();\n> +\n>  \tvideo_->streamOff();\n>  \tvideo_->releaseBuffers();\n> +\n> +\tconverterBuffers_.clear();\n>  \tactiveCamera_ = nullptr;\n>  }\n>  \n> @@ -552,6 +623,15 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)\n>  \t\treturn -ENOENT;\n>  \t}\n>  \n> +\t/*\n> +\t * If conversion is needed, push the buffer to the converter queue, it\n> +\t * will be handed to the converter in the capture completion handler.\n> +\t */\n> +\tif (useConverter_) {\n> +\t\tconverterQueue_.push(buffer);\n> +\t\treturn 0;\n> +\t}\n> +\n>  \treturn video_->queueBuffer(buffer);\n>  }\n>  \n> @@ -561,16 +641,25 @@ int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)\n>  \n>  bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n>  {\n> -\tstatic const char * const drivers[] = {\n> -\t\t\"imx7-csi\",\n> -\t\t\"sun6i-csi\",\n> +\tstatic const SimplePipelineInfo infos[] = {\n> +\t\t{ \"imx7-csi\", \"pxp\" },\n> +\t\t{ \"sun6i-csi\", nullptr },\n>  \t};\n\nPerhaps this comment really applies to the original addition of this\narray, but I think as this structure defines what the\nSimplePipelineHandler supports, it would be beneficial to have it as\nhigh up in the code file as possible. (in this instance just after, or\nas part of defining the SimplePipelineInfo structure.\n\nWhen someone wants to add their device to the list, it \"should\" be the\nonly thing they need to change, so the table should be at the beginning\nof the file where it is easy/instant to find.\n\n--\nKieran\n\n\n\n>  \n> -\tfor (const char *driver : drivers) {\n> -\t\tDeviceMatch dm(driver);\n> +\tMediaDevice *converter = nullptr;\n> +\n> +\tfor (const SimplePipelineInfo &info : infos) {\n> +\t\tDeviceMatch dm(info.driver);\n>  \t\tmedia_ = acquireMediaDevice(enumerator, dm);\n> -\t\tif (media_)\n> +\t\tif (!media_)\n> +\t\t\tcontinue;\n> +\n> +\t\tif (!info.converter)\n>  \t\t\tbreak;\n> +\n> +\t\tDeviceMatch converterMatch(info.converter);\n> +\t\tconverter = acquireMediaDevice(enumerator, converterMatch);\n> +\t\tbreak;\n>  \t}\n>  \n>  \tif (!media_)\n> @@ -625,6 +714,19 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator)\n>  \n>  \tvideo_->bufferReady.connect(this, &SimplePipelineHandler::bufferReady);\n>  \n> +\t/* Open the converter, if any. */\n> +\tif (converter) {\n> +\t\tconverter_ = new SimpleConverter(converter);\n> +\t\tif (converter_->open() < 0) {\n> +\t\t\tLOG(SimplePipeline, Warning)\n> +\t\t\t\t<< \"Failed to open converter, disabling format conversion\";\n> +\t\t\tdelete converter_;\n> +\t\t\tconverter_ = nullptr;\n> +\t\t}\n> +\n> +\t\tconverter_->bufferReady.connect(this, &SimplePipelineHandler::converterDone);\n> +\t}\n> +\n>  \t/*\n>  \t * Create one camera data instance for each sensor and gather all\n>  \t * entities in all pipelines.\n> @@ -699,12 +801,70 @@ V4L2Subdevice *SimplePipelineHandler::subdev(const MediaEntity *entity)\n>  \n>  void SimplePipelineHandler::bufferReady(FrameBuffer *buffer)\n>  {\n> -\tASSERT(activeCamera_);\n> +\t/*\n> +\t * If an error occurred during capture, or if the buffer was cancelled,\n> +\t * complete the request, even if the converter is in use as there's no\n> +\t * point converting an erroneous buffer.\n> +\t */\n> +\tif (buffer->metadata().status != FrameMetadata::FrameSuccess) {\n> +\t\tif (useConverter_) {\n> +\t\t\t/* Requeue the buffer for capture. */\n> +\t\t\tvideo_->queueBuffer(buffer);\n> +\n> +\t\t\t/*\n> +\t\t\t * Get the next user-facing buffer to complete the\n> +\t\t\t * request.\n> +\t\t\t */\n> +\t\t\tif (converterQueue_.empty())\n> +\t\t\t\treturn;\n> +\n> +\t\t\tbuffer = converterQueue_.front();\n> +\t\t\tconverterQueue_.pop();\n> +\t\t}\n> +\n> +\t\tRequest *request = buffer->request();\n> +\t\tcompleteBuffer(activeCamera_, request, buffer);\n> +\t\tcompleteRequest(activeCamera_, request);\n> +\t\treturn;\n> +\t}\n> +\n> +\t/*\n> +\t * Queue the captured and the request buffer to the converter if format\n> +\t * conversion is needed. If there's no queued request, just requeue the\n> +\t * captured buffer for capture.\n> +\t */\n> +\tif (useConverter_) {\n> +\t\tif (converterQueue_.empty()) {\n> +\t\t\tvideo_->queueBuffer(buffer);\n> +\t\t\treturn;\n> +\t\t}\n> +\n> +\t\tFrameBuffer *output = converterQueue_.front();\n> +\t\tconverterQueue_.pop();\n> +\n> +\t\tconverter_->queueBuffers(buffer, output);\n> +\t\treturn;\n> +\t}\n> +\n> +\t/* Otherwise simply complete the request. */\n>  \tRequest *request = buffer->request();\n>  \tcompleteBuffer(activeCamera_, request, buffer);\n>  \tcompleteRequest(activeCamera_, request);\n>  }\n>  \n> +void SimplePipelineHandler::converterDone(FrameBuffer *input,\n> +\t\t\t\t\t  FrameBuffer *output)\n> +{\n> +\t/* Complete the request. */\n> +\tASSERT(activeCamera_);\n> +\tRequest *request = output->request();\n> +\tcompleteBuffer(activeCamera_, request, output);\n> +\tcompleteRequest(activeCamera_, request);\n> +\n> +\t/* Queue the input buffer back for capture. */\n> +\tvideo_->queueBuffer(input);\n> +}\n> +\n>  REGISTER_PIPELINE_HANDLER(SimplePipelineHandler);\n>  \n>  } /* namespace libcamera */\n>","headers":{"Return-Path":"<kieran.bingham@ideasonboard.com>","Received":["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 9393B6040B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 31 Mar 2020 14:43:06 +0200 (CEST)","from [192.168.0.20]\n\t(cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id D2951B18;\n\tTue, 31 Mar 2020 14:43:05 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"jmOCSW9a\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1585658586;\n\tbh=lQwB9Oz5s1ChPWkhPm8i8xkjDhCD97OIkCocKQ7ba4s=;\n\th=Reply-To:Subject:To:Cc:References:From:Date:In-Reply-To:From;\n\tb=jmOCSW9aVFB9DU0njwmpsS2+5rnPSBl5ccPeoYAA+mOUkhvVZ0L4/0pz2K+xosgiq\n\tvjHyfFs7kSgufgI2jhE9U43sOnh7O8qPd5HAQ0lfS/snaswRlKJxxh78lqsd0lfptu\n\tgfiSB5nda0Qj3aEb2cThqZVrEZhW6fCcFtuHo/8U=","Reply-To":"kieran.bingham@ideasonboard.com","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","Cc":"Martijn Braam <martijn@brixit.nl>,\n\tBenjamin GAIGNARD <benjamin.gaignard@st.com>","References":"<20200320014839.14683-1-laurent.pinchart@ideasonboard.com>\n\t<20200320014839.14683-12-laurent.pinchart@ideasonboard.com>","From":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Openpgp":"preference=signencrypt","Autocrypt":"addr=kieran.bingham@ideasonboard.com; keydata=\n\tmQINBFYE/WYBEACs1PwjMD9rgCu1hlIiUA1AXR4rv2v+BCLUq//vrX5S5bjzxKAryRf0uHat\n\tV/zwz6hiDrZuHUACDB7X8OaQcwhLaVlq6byfoBr25+hbZG7G3+5EUl9cQ7dQEdvNj6V6y/SC\n\trRanWfelwQThCHckbobWiQJfK9n7rYNcPMq9B8e9F020LFH7Kj6YmO95ewJGgLm+idg1Kb3C\n\tpotzWkXc1xmPzcQ1fvQMOfMwdS+4SNw4rY9f07Xb2K99rjMwZVDgESKIzhsDB5GY465sCsiQ\n\tcSAZRxqE49RTBq2+EQsbrQpIc8XiffAB8qexh5/QPzCmR4kJgCGeHIXBtgRj+nIkCJPZvZtf\n\tKr2EAbc6tgg6DkAEHJb+1okosV09+0+TXywYvtEop/WUOWQ+zo+Y/OBd+8Ptgt1pDRyOBzL8\n\tRXa8ZqRf0Mwg75D+dKntZeJHzPRJyrlfQokngAAs4PaFt6UfS+ypMAF37T6CeDArQC41V3ko\n\tlPn1yMsVD0p+6i3DPvA/GPIksDC4owjnzVX9kM8Zc5Cx+XoAN0w5Eqo4t6qEVbuettxx55gq\n\t8K8FieAjgjMSxngo/HST8TpFeqI5nVeq0/lqtBRQKumuIqDg+Bkr4L1V/PSB6XgQcOdhtd36\n\tOe9X9dXB8YSNt7VjOcO7BTmFn/Z8r92mSAfHXpb07YJWJosQOQARAQABtDBLaWVyYW4gQmlu\n\tZ2hhbSA8a2llcmFuLmJpbmdoYW1AaWRlYXNvbmJvYXJkLmNvbT6JAlcEEwEKAEECGwMFCwkI\n\tBwIGFQgJCgsCBBYCAwECHgECF4ACGQEWIQSQLdeYP70o/eNy1HqhHkZyEKRh/QUCXWTtygUJ\n\tCyJXZAAKCRChHkZyEKRh/f8dEACTDsbLN2nioNZMwyLuQRUAFcXNolDX48xcUXsWS2QjxaPm\n\tVsJx8Uy8aYkS85mdPBh0C83OovQR/OVbr8AxhGvYqBs3nQvbWuTl/+4od7DfK2VZOoKBAu5S\n\tQK2FYuUcikDqYcFWJ8DQnubxfE8dvzojHEkXw0sA4igINHDDFX3HJGZtLio+WpEFQtCbfTAG\n\tYZslasz1YZRbwEdSsmO3/kqy5eMnczlm8a21A3fKUo3g8oAZEFM+f4DUNzqIltg31OAB/kZS\n\tenKZQ/SWC8PmLg/ZXBrReYakxXtkP6w3FwMlzOlhGxqhIRNiAJfXJBaRhuUWzPOpEDE9q5YJ\n\tBmqQL2WJm1VSNNVxbXJHpaWMH1sA2R00vmvRrPXGwyIO0IPYeUYQa3gsy6k+En/aMQJd27dp\n\taScf9am9PFICPY5T4ppneeJLif2lyLojo0mcHOV+uyrds9XkLpp14GfTkeKPdPMrLLTsHRfH\n\tfA4I4OBpRrEPiGIZB/0im98MkGY/Mu6qxeZmYLCcgD6qz4idOvfgVOrNh+aA8HzIVR+RMW8H\n\tQGBN9f0E3kfwxuhl3omo6V7lDw8XOdmuWZNC9zPq1UfryVHANYbLGz9KJ4Aw6M+OgBC2JpkD\n\thXMdHUkC+d20dwXrwHTlrJi1YNp6rBc+xald3wsUPOZ5z8moTHUX/uPA/qhGsbkCDQRWBP1m\n\tARAAzijkb+Sau4hAncr1JjOY+KyFEdUNxRy+hqTJdJfaYihxyaj0Ee0P0zEi35CbE6lgU0Uz\n\ttih9fiUbSV3wfsWqg1Ut3/5rTKu7kLFp15kF7eqvV4uezXRD3Qu4yjv/rMmEJbbD4cTvGCYI\n\td6MDC417f7vK3hCbCVIZSp3GXxyC1LU+UQr3fFcOyCwmP9vDUR9JV0BSqHHxRDdpUXE26Dk6\n\tmhf0V1YkspE5St814ETXpEus2urZE5yJIUROlWPIL+hm3NEWfAP06vsQUyLvr/GtbOT79vXl\n\tEn1aulcYyu20dRRxhkQ6iILaURcxIAVJJKPi8dsoMnS8pB0QW12AHWuirPF0g6DiuUfPmrA5\n\tPKe56IGlpkjc8cO51lIxHkWTpCMWigRdPDexKX+Sb+W9QWK/0JjIc4t3KBaiG8O4yRX8ml2R\n\t+rxfAVKM6V769P/hWoRGdgUMgYHFpHGSgEt80OKK5HeUPy2cngDUXzwrqiM5Sz6Od0qw5pCk\n\tNlXqI0W/who0iSVM+8+RmyY0OEkxEcci7rRLsGnM15B5PjLJjh1f2ULYkv8s4SnDwMZ/kE04\n\t/UqCMK/KnX8pwXEMCjz0h6qWNpGwJ0/tYIgQJZh6bqkvBrDogAvuhf60Sogw+mH8b+PBlx1L\n\toeTK396wc+4c3BfiC6pNtUS5GpsPMMjYMk7kVvEAEQEAAYkCPAQYAQoAJgIbDBYhBJAt15g/\n\tvSj943LUeqEeRnIQpGH9BQJdizzIBQkLSKZiAAoJEKEeRnIQpGH9eYgQAJpjaWNgqNOnMTmD\n\tMJggbwjIotypzIXfhHNCeTkG7+qCDlSaBPclcPGYrTwCt0YWPU2TgGgJrVhYT20ierN8LUvj\n\t6qOPTd+Uk7NFzL65qkh80ZKNBFddx1AabQpSVQKbdcLb8OFs85kuSvFdgqZwgxA1vl4TFhNz\n\tPZ79NAmXLackAx3sOVFhk4WQaKRshCB7cSl+RIng5S/ThOBlwNlcKG7j7W2MC06BlTbdEkUp\n\tECzuuRBv8wX4OQl+hbWbB/VKIx5HKlLu1eypen/5lNVzSqMMIYkkZcjV2SWQyUGxSwq0O/sx\n\tS0A8/atCHUXOboUsn54qdxrVDaK+6jIAuo8JiRWctP16KjzUM7MO0/+4zllM8EY57rXrj48j\n\tsbEYX0YQnzaj+jO6kJtoZsIaYR7rMMq9aUAjyiaEZpmP1qF/2sYenDx0Fg2BSlLvLvXM0vU8\n\tpQk3kgDu7kb/7PRYrZvBsr21EIQoIjXbZxDz/o7z95frkP71EaICttZ6k9q5oxxA5WC6sTXc\n\tMW8zs8avFNuA9VpXt0YupJd2ijtZy2mpZNG02fFVXhIn4G807G7+9mhuC4XG5rKlBBUXTvPU\n\tAfYnB4JBDLmLzBFavQfvonSfbitgXwCG3vS+9HEwAjU30Bar1PEOmIbiAoMzuKeRm2LVpmq4\n\tWZw01QYHU/GUV/zHJSFk","Organization":"Ideas on Board","Message-ID":"<092cc1db-fcda-b605-b4f7-e8399c830db7@ideasonboard.com>","Date":"Tue, 31 Mar 2020 13:43:03 +0100","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101\n\tThunderbird/60.9.1","MIME-Version":"1.0","In-Reply-To":"<20200320014839.14683-12-laurent.pinchart@ideasonboard.com>","Content-Type":"text/plain; charset=utf-8","Content-Language":"en-GB","Content-Transfer-Encoding":"7bit","Subject":"Re: [libcamera-devel] [PATCH v3 11/11] libcamera: pipeline: simple:\n\tIntegrate converter support","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>","X-List-Received-Date":"Tue, 31 Mar 2020 12:43:06 -0000"}}]