[{"id":843,"web_url":"https://patchwork.libcamera.org/comment/843/","msgid":"<20190222002838.GN3485@pendragon.ideasonboard.com>","date":"2019-02-22T00:28:38","subject":"Re: [libcamera-devel] [PATCH 5/5] libcamera: ipu3: Add IMGUDevice\n\tclass","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Wed, Feb 20, 2019 at 02:17:57PM +0100, Jacopo Mondi wrote:\n> Add an IMGUDevice class that represents all devices associated with the\n> IPU3 imgu unit.\n\ns/imgu/ImgU/\n\n> \n> Imgu units will be freely assigned to cameras, depending on the number of\n\ns/Imgu/ImgU/\n\n> streams that are required. Add two imgu instances to the ipu3 pipeline,\n\nSame here and everywhere else, and s/ipu3/IPU3/\n\n> and provide methods to configure the format on the imgu internal\n> components.\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  src/libcamera/pipeline/ipu3/imgu.cpp    | 338 ++++++++++++++++++++++++\n>  src/libcamera/pipeline/ipu3/ipu3.cpp    |  71 +++++\n>  src/libcamera/pipeline/ipu3/ipu3.h      |  34 +++\n>  src/libcamera/pipeline/ipu3/meson.build |   1 +\n>  4 files changed, 444 insertions(+)\n>  create mode 100644 src/libcamera/pipeline/ipu3/imgu.cpp\n> \n> diff --git a/src/libcamera/pipeline/ipu3/imgu.cpp b/src/libcamera/pipeline/ipu3/imgu.cpp\n> new file mode 100644\n> index 000000000000..7945764eb989\n> --- /dev/null\n> +++ b/src/libcamera/pipeline/ipu3/imgu.cpp\n> @@ -0,0 +1,338 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2019, Google Inc.\n> + *\n> + * imgu.cpp - IPU3 IMGU unit\n> + */\n> +\n> +#include <string>\n> +#include <vector>\n> +\n> +#include <linux/media-bus-format.h>\n> +\n> +#include \"geometry.h\"\n> +#include \"ipu3.h\"\n> +#include \"media_device.h\"\n> +#include \"v4l2_device.h\"\n> +#include \"v4l2_subdevice.h\"\n> +\n> +/*\n> + * IMGUDevice represents one of the two 'IMGU' units the Intel IPU3 ISP\n\nHow about naming the class ImgUDevice ?\n\n> + * provides.\n> + *\n> + * IMGU units are fed with image data captured from a CIO2 instance and with\n> + * configuration parameters for 3A tuning.\n> + *\n> + * Each IMGU handles 2 video pipes at the time, and each pipe provide 2 image\n\nDid you mean \"at the same time\" ?\n\ns/provide/provides/\n\n> + * outputs ('output' and 'viewfinder') and one statistics metadata output.\n> + *\n> + * TODO: support concurrent pipes\n> + * TODO: support multiple video capture streams (output + viewfinder)\n> + */\n> +\n> +namespace libcamera {\n> +\n> +LOG_DECLARE_CATEGORY(IPU3)\n> +\n> +IMGUDevice::IMGUDevice()\n> +\t: owner_(nullptr), imgu_(nullptr), input_(nullptr),\n> +\t  output_(nullptr), viewfinder_(nullptr), stat_(nullptr)\n> +{\n> +}\n> +\n> +IMGUDevice::~IMGUDevice()\n> +{\n> +\tdelete imgu_;\n> +\tdelete input_;\n> +\tdelete output_;\n> +\tdelete viewfinder_;\n> +\tdelete stat_;\n> +}\n> +\n> +int IMGUDevice::open(unsigned int index, MediaDevice *imguMediaDev)\n\nSame comment as for CIO2Device, here and through this function.\n\n> +{\n> +\tint ret;\n> +\n> +\tstd::string imguName = \"ipu3-imgu \" + std::to_string(index);\n> +\tMediaEntity *entity = imguMediaDev->getEntityByName(imguName);\n> +\tif (!entity) {\n> +\t\tLOG(IPU3, Error) << \"Failed to get entity '\" << imguName << \"'\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\timgu_ = new V4L2Subdevice(entity);\n> +\tret = imgu_->open();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tstd::string inputName = imguName + \" input\";\n> +\tentity = imguMediaDev->getEntityByName(inputName);\n> +\tif (!entity) {\n> +\t\tLOG(IPU3, Error) << \"Failed to get entity '\" << inputName << \"'\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\tinput_ = new V4L2Device(entity);\n> +\tret = input_->open();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tstd::string outputName = imguName + \" output\";\n> +\tentity = imguMediaDev->getEntityByName(outputName);\n> +\tif (!entity) {\n> +\t\tLOG(IPU3, Error) << \"Failed to get entity '\" << outputName << \"'\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\toutput_ = new V4L2Device(entity);\n> +\tret = output_->open();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tstd::string viewfinderName = imguName + \" viewfinder\";\n> +\tentity = imguMediaDev->getEntityByName(viewfinderName);\n> +\tif (!entity) {\n> +\t\tLOG(IPU3, Error) << \"Failed to get entity '\"\n> +\t\t\t\t << viewfinderName << \"'\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\tviewfinder_ = new V4L2Device(entity);\n> +\tret = viewfinder_->open();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tstd::string statName = imguName + \" 3a stat\";\n> +\tentity = imguMediaDev->getEntityByName(statName);\n> +\tif (!entity) {\n> +\t\tLOG(IPU3, Error) << \"Failed to get entity '\"\n> +\t\t\t\t << statName << \"'\";\n> +\t\treturn -ENODEV;\n> +\t}\n> +\n> +\tstat_ = new V4L2Device(entity);\n> +\tret = stat_->open();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\t/* Link entities to configure the IMGU unit for capture. */\n> +\tMediaLink *link = imguMediaDev->link(inputName, 0, imguName, 0);\n\nShouldn't you use the constants you defined for pad numbers ?\n\n> +\tif (!link) {\n> +\t\tLOG(IPU3, Error)\n> +\t\t\t<< \"Failed to get link '\" << inputName << \"':0 -> '\"\n> +\t\t\t<< imguName << \"':0\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tlink->setEnabled(true);\n> +\n> +\tlink = imguMediaDev->link(imguName, 2, outputName, 0);\n> +\tif (!link) {\n> +\t\tLOG(IPU3, Error)\n> +\t\t\t<< \"Failed to get link '\" << imguName << \"':2 -> '\"\n> +\t\t\t<< outputName << \"':0\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tlink->setEnabled(true);\n> +\n> +\tlink = imguMediaDev->link(imguName, 3, viewfinderName, 0);\n> +\tif (!link) {\n> +\t\tLOG(IPU3, Error)\n> +\t\t\t<< \"Failed to get link '\" << imguName << \"':3 -> '\"\n> +\t\t\t<< viewfinderName << \"':0\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tlink->setEnabled(true);\n> +\n> +\tlink = imguMediaDev->link(imguName, 4, statName, 0);\n> +\tif (!link) {\n> +\t\tLOG(IPU3, Error)\n> +\t\t\t<< \"Failed to get link '\" << imguName << \"':4 -> '\"\n> +\t\t\t<< statName << \"':0\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tlink->setEnabled(true);\n> +\n> +\treturn 0;\n> +}\n> +\n> +int IMGUDevice::configure(const IPU3DeviceFormat &inputFormat,\n> +\t\t\t  const IPU3DeviceFormat &outputFormat)\n> +{\n> +\tint ret;\n> +\n> +\tRectangle selectionRectangle = {};\n\nMaybe just rectangle or rect ? Let's not use long names needlessly.\n\n> +\tselectionRectangle.x = 0;\n> +\tselectionRectangle.y = 0;\n> +\tselectionRectangle.w = inputFormat.width;\n> +\tselectionRectangle.h = inputFormat.height;\n\nCan't you initialize the rectangle when declaring it ?\n\n> +\n> +\tret = imgu_->setCrop(IMGU_PAD_INPUT, selectionRectangle);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_INPUT << \" = \"\n> +\t\t<< \"crop: (0,0)/\" << selectionRectangle.w << \"x\"\n> +\t\t<< selectionRectangle.h;\n> +\n> +\tret = imgu_->setCompose(IMGU_PAD_INPUT, selectionRectangle);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_INPUT << \" = \"\n> +\t\t<< \"compose: (0,0)/\" << selectionRectangle.w << \"x\"\n> +\t\t<< selectionRectangle.h;\n> +\n> +\tV4L2SubdeviceFormat subdevFormat = {};\n> +\tret = imgu_->getFormat(IMGU_PAD_INPUT, &subdevFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_INPUT << \" = \"\n> +\t\t<< subdevFormat.width << \"x\" << subdevFormat.height << \" - \"\n> +\t\t<< std::hex << subdevFormat.mbus_code;\n> +\n> +\t/*\n> +\t * Apply image format to the 'imgu' unit subdevices.\n> +\t *\n> +\t * FIXME: the IPU3 driver implementation shall be changed to use the\n> +\t * actual input sizes as 'imgu input' subdevice sizes, and use the\n> +\t * desired output sizes to configure the crop/compose rectangles.  The\n> +\t * current implementation uses output sizes as 'imgu input' sizes, and\n> +\t * uses the input dimension to configure the crop/compose rectangles,\n> +\t * which contradicts the V4L2 specifications.\n> +\t */\n> +\tsubdevFormat = {};\n> +\tsubdevFormat.width = outputFormat.width;\n> +\tsubdevFormat.height = outputFormat.height;\n> +\tsubdevFormat.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10;\n> +\n> +\tret = imgu_->setFormat(IMGU_PAD_INPUT, &subdevFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_INPUT << \" = \"\n> +\t\t<< subdevFormat.width << \"x\" << subdevFormat.height << \" - \"\n> +\t\t<< std::hex << subdevFormat.mbus_code;\n> +\n> +\t/*\n> +\t * Configure the 'imgu output' and 'imgu 3a stat' pads with the\n> +\t * desired output image sizes.\n> +\t */\n> +\tsubdevFormat = {};\n> +\tsubdevFormat.width = outputFormat.width;;\n> +\tsubdevFormat.height = outputFormat.height;\n> +\tsubdevFormat.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10;\n> +\n> +\tret = imgu_->setFormat(IMGU_PAD_OUTPUT, &subdevFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_OUTPUT << \" = \"\n> +\t\t<< subdevFormat.width << \"x\" << subdevFormat.height << \" - \"\n> +\t\t<< std::hex << subdevFormat.mbus_code;\n> +\n> +\tsubdevFormat = {};\n> +\tsubdevFormat.width = outputFormat.width;;\n> +\tsubdevFormat.height = outputFormat.height;\n> +\tsubdevFormat.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10;\n> +\n> +\tret = imgu_->setFormat(IMGU_PAD_STAT, &subdevFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_STAT << \" = \"\n> +\t\t<< subdevFormat.width << \"x\" << subdevFormat.height << \" - \"\n> +\t\t<< std::hex << subdevFormat.mbus_code;\n> +\n> +\t/*\n> +\t * FIXME: Set the 'imgu viewfinder' to hardcoded size\n> +\t * It shall be configured as secondary stream when support for\n> +\t * multiple streams is added.\n> +\t */\n> +\tsubdevFormat = {};\n> +\tsubdevFormat.width = outputFormat.width / 2;\n> +\tsubdevFormat.height = outputFormat.height / 2;\n> +\tsubdevFormat.mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10;\n> +\n> +\tret = imgu_->setFormat(IMGU_PAD_VF, &subdevFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << imgu_->deviceName() << \"':\" << IMGU_PAD_VF << \" = \"\n> +\t\t<< subdevFormat.width << \"x\" << subdevFormat.height << \" - \"\n> +\t\t<< std::hex << subdevFormat.mbus_code;\n> +\n> +\t/*\n> +\t * Apply the CIO2 provided 'inputFormat' to the 'imgu input' video\n> +\t * device, and the requested 'outputFormat' to the to the 'imgu output'\n> +\t * 'imgu viewfinder' and 'imgu 3a stat' nodes.\n> +\t *\n> +\t * FIXME: Keep the viewfinder size reduced.\n> +\t */\n> +\tV4L2DeviceFormat devFormat = {};\n> +\tdevFormat.width = inputFormat.width;\n> +\tdevFormat.height = inputFormat.height;\n> +\tdevFormat.fourcc = inputFormat.fourcc;\n> +\n> +\tret = input_->setFormat(&devFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << input_->driverName() << \"': \"\n> +\t\t<< devFormat.width << \"x\" << devFormat.height\n> +\t\t<< \"- 0x\" << std::hex << devFormat.fourcc << \" planes: \"\n> +\t\t<< devFormat.planesCount;\n> +\n> +\tdevFormat = {};\n> +\tdevFormat.width = outputFormat.width;\n> +\tdevFormat.height = outputFormat.height;\n> +\tdevFormat.fourcc = outputFormat.fourcc;\n> +\tV4L2DeviceFormat tmpFormat = devFormat;\n> +\n> +\tret = output_->setFormat(&tmpFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << output_->driverName() << \"': \"\n> +\t\t<< tmpFormat.width << \"x\" << tmpFormat.height\n> +\t\t<< \"- 0x\" << std::hex << tmpFormat.fourcc << \" planes: \"\n> +\t\t<< tmpFormat.planesCount;\n> +\n> +\ttmpFormat = devFormat;\n> +\tret = stat_->setFormat(&tmpFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << stat_->driverName() << \"': \"\n> +\t\t<< tmpFormat.width << \"x\" << tmpFormat.height\n> +\t\t<< \"- 0x\" << std::hex << tmpFormat.fourcc << \" planes: \"\n> +\t\t<< tmpFormat.planesCount;\n> +\n> +\ttmpFormat = devFormat;\n> +\ttmpFormat.width = devFormat.width / 2;\n> +\ttmpFormat.height = devFormat.height / 2;\n> +\n> +\tret = viewfinder_->setFormat(&tmpFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\tLOG(IPU3, Debug)\n> +\t\t<< \"'\" << viewfinder_->driverName() << \"': \"\n> +\t\t<< tmpFormat.width << \"x\" << tmpFormat.height\n> +\t\t<< \"- 0x\" << std::hex << tmpFormat.fourcc << \" planes: \"\n> +\t\t<< tmpFormat.planesCount;\n> +\n> +\treturn 0;\n> +}\n> +\n> +} /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index 5fcdd6335db6..8b4c88048f6c 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -64,6 +64,7 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera,\n>  \tStream *stream = &cameraData(camera)->stream_;\n>  \tStreamConfiguration *cfg = &config[stream];\n>  \tIPU3DeviceFormat outputFormat = {};\n> +\tIMGUDevice *imgu;\n>  \tint ret;\n>  \n>  \t/* Validate the requested image format and resolution. */\n> @@ -75,10 +76,46 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera,\n>  \toutputFormat.height = cfg->height;\n>  \toutputFormat.fourcc = cfg->pixelFormat;\n>  \n> +\t/*\n> +\t * FIXME: as of now, a single stream is supported, so we can claim\n> +\t * the first available imgu unit, if any. When multiple streams per\n> +\t * camera will be supported, a single camera could use both the imgu\n\ns/both the imgu units/both ImgUs/ (U stands for unit)\n\n> +\t * units and prevent other cameras to be used.\n\ns/to be used/from being used/\n\n> +\t */\n> +\tif (imgu0_.available())\n> +\t\timgu = &imgu0_;\n> +\telse if (imgu1_.available())\n> +\t\timgu = &imgu1_;\n> +\telse\n> +\t\treturn -EBUSY;\n\nYou can just use imgu0_ unconditionally for now.\n\n> +\t/*\n> +\t * FIXME: the imgu unit shall be released when streams gets released.\n> +\t * How to deal with cross-camera dependencies ?\n> +\t */\n> +\timgu->acquire(camera);\n> +\n> +\t/*\n> +\t * Configure the CIO2 unit to provide images in a resolution that\n> +\t * satisfies the desired output format.\n> +\t */\n>  \tret = cio2->configure(outputFormat);\n>  \tif (ret)\n>  \t\treturn ret;\n>  \n> +\t/*\n> +\t * Get the CIO2 output format and apply it to the IMGU input and\n> +\t * apply the output format to the IMGU output.\n> +\t *\n> +\t * Hardcode the fourcc code output from CIO2 to IMGU.\n> +\t */\n> +\tIPU3DeviceFormat inputFormat = cio2->format();\n> +\tinputFormat.fourcc = V4L2_PIX_FMT_IPU3_SGRBG10;\n\nShould cio2->format() provide the right fourcc already ?\n\n> +\n> +\tret = imgu->configure(inputFormat, outputFormat);\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n>  \treturn 0;\n>  }\n>  \n> @@ -205,12 +242,22 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)\n>  \tif (cio2_->disableLinks())\n>  \t\tgoto error_close_cio2;\n>  \n> +\tif (imgu_->open())\n> +\t\tgoto error_close_cio2;\n> +\n>  \tregisterCameras();\n>  \n> +\tif (registerImgus())\n> +\t\tgoto error_close_imgu;\n> +\n>  \tcio2_->close();\n> +\timgu_->close();\n>  \n>  \treturn true;\n>  \n> +error_close_imgu:\n> +\timgu_->close();\n> +\n>  error_close_cio2:\n>  \tcio2_->close();\n\nYou can close an unopened device, so let's go for a single error label,\nit makes code simpler.\n\n>  \n> @@ -221,6 +268,30 @@ error_release_mdev:\n>  \treturn false;\n>  }\n>  \n> +/*\n> + * IPU3 has two 'imgu' units which can be freely assigned to cameras;\n\ns/has two 'imgu' units which/two ImgUs that/\ns/;/./\n\n> + *\n> + * Create instances for both the units, creating video devices and subdevices\n\ns/both the units/both units/\n\n> + * associated with an instance.\n\nYou open the instances, you don't create them.\n\n> + */\n> +\n> +int PipelineHandlerIPU3::registerImgus()\n\nThe ImgUs are not registered anywhere, this function should be renamed.\n\n> +{\n> +\tint ret = imgu0_.open(0, imgu_.get());\n> +\tif (ret) {\n> +\t\tLOG(IPU3, Error) << \"Failed to open 'imgu0' unit\";\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tret = imgu1_.open(1, imgu_.get());\n> +\tif (ret) {\n> +\t\tLOG(IPU3, Error) << \"Failed to open 'imgu1' unit\";\n> +\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n>  /*\n>   * Cameras are created associating an image sensor (represented by a\n>   * media entity with function MEDIA_ENT_F_CAM_SENSOR) to one of the four\n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.h b/src/libcamera/pipeline/ipu3/ipu3.h\n> index 2a8b6f13b1c7..83d6e7cf27db 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.h\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.h\n> @@ -57,6 +57,36 @@ public:\n>  \tIPU3DeviceFormat cio2Format_;\n>  };\n>  \n> +class IMGUDevice\n> +{\n> +public:\n> +\tstatic constexpr unsigned int IMGU_PAD_INPUT = 0;\n> +\tstatic constexpr unsigned int IMGU_PAD_OUTPUT = 2;\n> +\tstatic constexpr unsigned int IMGU_PAD_VF = 3;\n> +\tstatic constexpr unsigned int IMGU_PAD_STAT = 4;\n\nI wonder if static is needed here.\n\n> +\n> +\tIMGUDevice();\n> +\tIMGUDevice(const IMGUDevice &) = delete;\n\nShould you delete the copy assignement operator too ?\n\n> +\t~IMGUDevice();\n> +\n> +\tCamera *owner_;\n> +\tbool available() const { return owner_ == nullptr; }\n> +\tvoid acquire(Camera *camera) { owner_ = camera; }\n> +\tvoid release() { owner_ = nullptr; }\n\nWe don't know yet how we will deal with ownership, so for now I'd drop\nthis.\n\n> +\n> +\tint open(unsigned int index, MediaDevice *imguMediaDev);\n\nMissing close().\n\n> +\n> +\tint configure(const IPU3DeviceFormat &cio2Format,\n> +\t\t      const IPU3DeviceFormat &imguFormat);\n> +\n> +\tV4L2Subdevice *imgu_;\n> +\tV4L2Device *input_;\n> +\tV4L2Device *output_;\n> +\tV4L2Device *viewfinder_;\n> +\tV4L2Device *stat_;\n> +\t/* TODO: add param video device for 3A tuning */\n> +};\n> +\n>  class PipelineHandlerIPU3 : public PipelineHandler\n>  {\n>  public:\n> @@ -95,10 +125,14 @@ private:\n>  \t\t\tPipelineHandler::cameraData(camera));\n>  \t}\n>  \n> +\tint registerImgus();\n>  \tvoid registerCameras();\n>  \n>  \tstd::shared_ptr<MediaDevice> cio2_;\n>  \tstd::shared_ptr<MediaDevice> imgu_;\n> +\n> +\tIMGUDevice imgu0_;\n> +\tIMGUDevice imgu1_;\n>  };\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/ipu3/meson.build b/src/libcamera/pipeline/ipu3/meson.build\n> index fcb2d319d517..67f1a5e656d9 100644\n> --- a/src/libcamera/pipeline/ipu3/meson.build\n> +++ b/src/libcamera/pipeline/ipu3/meson.build\n> @@ -1,4 +1,5 @@\n>  libcamera_sources += files([\n>      'cio2.cpp',\n> +    'imgu.cpp',\n>      'ipu3.cpp',\n>  ])","headers":{"Return-Path":"<laurent.pinchart@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 4E1F1600FB\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 22 Feb 2019 01:28:43 +0100 (CET)","from pendragon.ideasonboard.com\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id B9D49255;\n\tFri, 22 Feb 2019 01:28:42 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1550795322;\n\tbh=5b0uWdZ78vSsRlfm85TmjhcGe0144jxB+kUb1JU5MNc=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=YnAiEjP8UmOesYZ5o1HgwnX/taL962JNQ4HhNY/VQXwLsC1GmAdc3ufxxO5Zi/JZF\n\tMKfDe3FYN/ODsuZjLjR3VdXM+DPlim8ILx6cef+CCEf6vhNjvcCIFLGxjlUhDf1U9g\n\tvYR2rsd8hvWwDktttTtbKwbL8NszA9cdLUjrNa8A=","Date":"Fri, 22 Feb 2019 02:28:38 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190222002838.GN3485@pendragon.ideasonboard.com>","References":"<20190220131757.14004-1-jacopo@jmondi.org>\n\t<20190220131757.14004-6-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20190220131757.14004-6-jacopo@jmondi.org>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH 5/5] libcamera: ipu3: Add IMGUDevice\n\tclass","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 22 Feb 2019 00:28:43 -0000"}}]