[{"id":12412,"web_url":"https://patchwork.libcamera.org/comment/12412/","msgid":"<20200910110006.GK4095624@oden.dyn.berto.se>","date":"2020-09-10T11:00:06","subject":"Re: [libcamera-devel] [PATCH v3 09/11] android: camera_device:\n\tRework CameraStream handling","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Jacopo,\n\nThanks for your work.\n\nOn 2020-09-08 15:41:40 +0200, Jacopo Mondi wrote:\n> The CameraDevice::streams_ vector of CameraStream instances is\n> currently mostly accessed by index. The current implementation\n> creates all the CameraStream during the first loop that inspects the\n> camera3_stream instances, and the update the index of the\n> StreamConfiguration associated with the CameraStream during a second\n> loop that inspects MJPEG streams. A third loop creates the JPEG encoder\n> associated with CameraStreams that produce MJPEG format.\n> \n> As the index-based association is hard to follow and rather fragile,\n> rework the creation and handling of CameraStream:\n> \n> 1) Make the StreamConfiguration index a constructor parameter and a\n>    private struct member.  This disallow the creation of CameraStream\n>    without a StreamConfiguration index assigned.\n> \n> 2) Create CameraStream only after the associated StreamConfiguration\n>    has been identified. The first loop creates CameraStream for non-JPEG\n>    streams, the second for the JPEG ones after having identified the\n>    associated StreamConfiguration. Since we have just created the\n>    CameraStream, create the JPEG encoder at the same time instead of\n>    deferring it.\n> \n> This change removes all accesses by index to the CameraDevice::streams_\n> vector.\n> \n> No functional changes intended, but this change aims to make the code\n> easier to follow and more robust.\n> \n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  src/android/camera_device.cpp | 91 ++++++++++++++++++-----------------\n>  src/android/camera_device.h   | 18 ++++---\n>  2 files changed, 57 insertions(+), 52 deletions(-)\n> \n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index eab01d808917..e0260c92246c 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -168,8 +168,8 @@ MappedCamera3Buffer::MappedCamera3Buffer(const buffer_handle_t camera3buffer,\n>  \t}\n>  }\n>  \n> -CameraStream::CameraStream(PixelFormat f, Size s)\n> -\t: index(-1), format(f), size(s), jpeg(nullptr)\n> +CameraStream::CameraStream(PixelFormat f, Size s, unsigned int i)\n> +\t: format(f), size(s), jpeg(nullptr), index_(i)\n>  {\n>  }\n>  \n> @@ -1190,6 +1190,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \tstreams_.reserve(stream_list->num_streams);\n>  \n>  \t/* First handle all non-MJPEG streams. */\n> +\tcamera3_stream_t *jpegStream = nullptr;\n>  \tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n>  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n>  \t\tSize size(stream->width, stream->height);\n> @@ -1206,52 +1207,50 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \t\tif (!format.isValid())\n>  \t\t\treturn -EINVAL;\n>  \n> -\t\tstreams_.emplace_back(format, size);\n> -\t\tstream->priv = static_cast<void *>(&streams_[i]);\n> -\n>  \t\t/* Defer handling of MJPEG streams until all others are known. */\n> -\t\tif (stream->format == HAL_PIXEL_FORMAT_BLOB)\n> +\t\tif (stream->format == HAL_PIXEL_FORMAT_BLOB) {\n> +\t\t\tjpegStream = stream;\n>  \t\t\tcontinue;\n> +\t\t}\n>  \n>  \t\tStreamConfiguration streamConfiguration;\n> -\n>  \t\tstreamConfiguration.size = size;\n>  \t\tstreamConfiguration.pixelFormat = format;\n>  \n>  \t\tconfig_->addConfiguration(streamConfiguration);\n> -\t\tstreams_[i].index = config_->size() - 1;\n> +\t\tunsigned int index = config_->size() - 1;\n> +\t\tstreams_.emplace_back(format, size, index);\n> +\t\tstream->priv = static_cast<void *>(&streams_.back());\n\nIs this not dangerous? If the stremas_ vector is modified in any way the \nmembers may be reallocated and the pointer becomes invalid. I think this \nis what boost::container::stable_vector tries to solve for example.\n\n>  \t}\n>  \n>  \t/* Now handle MJPEG streams, adding a new stream if required. */\n> -\tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> -\t\tcamera3_stream_t *stream = stream_list->streams[i];\n> -\t\tbool match = false;\n> -\n> -\t\tif (stream->format != HAL_PIXEL_FORMAT_BLOB)\n> -\t\t\tcontinue;\n> +\tif (jpegStream) {\n> +\t\tint index = -1;\n>  \n> -\t\t/* Search for a compatible stream */\n> -\t\tfor (unsigned int j = 0; j < config_->size(); j++) {\n> -\t\t\tStreamConfiguration &cfg = config_->at(j);\n> +\t\t/* Search for a compatible stream in the non-JPEG ones. */\n> +\t\tfor (unsigned int i = 0; i < config_->size(); i++) {\n> +\t\t\tStreamConfiguration &cfg = config_->at(i);\n>  \n>  \t\t\t/*\n>  \t\t\t * \\todo The PixelFormat must also be compatible with\n>  \t\t\t * the encoder.\n>  \t\t\t */\n> -\t\t\tif (cfg.size == streams_[i].size) {\n> -\t\t\t\tLOG(HAL, Info) << \"Stream \" << i\n> -\t\t\t\t\t       << \" using libcamera stream \" << j;\n> +\t\t\tif (cfg.size.width != jpegStream->width ||\n> +\t\t\t    cfg.size.height != jpegStream->height)\n> +\t\t\t\tcontinue;\n>  \n> -\t\t\t\tmatch = true;\n> -\t\t\t\tstreams_[i].index = j;\n> -\t\t\t}\n> +\t\t\tLOG(HAL, Info)\n> +\t\t\t\t<< \"Android JPEG stream mapped on stream \" << i;\n> +\n> +\t\t\tindex = i;\n> +\t\t\tbreak;\n>  \t\t}\n>  \n>  \t\t/*\n>  \t\t * Without a compatible match for JPEG encoding we must\n>  \t\t * introduce a new stream to satisfy the request requirements.\n>  \t\t */\n> -\t\tif (!match) {\n> +\t\tif (index < 0) {\n>  \t\t\tStreamConfiguration streamConfiguration;\n>  \n>  \t\t\t/*\n> @@ -1260,15 +1259,31 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \t\t\t * handled, and should be considered as part of any\n>  \t\t\t * stream configuration reworks.\n>  \t\t\t */\n> -\t\t\tstreamConfiguration.size.width = stream->width;\n> -\t\t\tstreamConfiguration.size.height = stream->height;\n> +\t\t\tstreamConfiguration.size.width = jpegStream->width;\n> +\t\t\tstreamConfiguration.size.height = jpegStream->height;\n>  \t\t\tstreamConfiguration.pixelFormat = formats::NV12;\n>  \n>  \t\t\tLOG(HAL, Info) << \"Adding \" << streamConfiguration.toString()\n>  \t\t\t\t       << \" for MJPEG support\";\n>  \n>  \t\t\tconfig_->addConfiguration(streamConfiguration);\n> -\t\t\tstreams_[i].index = config_->size() - 1;\n> +\t\t\tindex = config_->size() - 1;\n> +\t\t}\n> +\n> +\t\tStreamConfiguration &cfg = config_->at(index);\n> +\t\tCameraStream &cameraStream =\n> +\t\t\tstreams_.emplace_back(formats::MJPEG, cfg.size, index);\n> +\t\tjpegStream->priv = static_cast<void *>(&cameraStream);\n> +\n> +\t\t/*\n> +\t\t * Construct a software encoder for MJPEG streams from the\n> +\t\t * chosen libcamera source stream.\n> +\t\t */\n> +\t\tcameraStream.jpeg = new EncoderLibJpeg();\n> +\t\tint ret = cameraStream.jpeg->configure(cfg);\n> +\t\tif (ret) {\n> +\t\t\tLOG(HAL, Error) << \"Failed to configure encoder\";\n> +\t\t\treturn ret;\n>  \t\t}\n>  \t}\n>  \n> @@ -1291,25 +1306,11 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \n>  \tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n>  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n> -\t\tCameraStream *cameraStream = &streams_[i];\n> -\t\tStreamConfiguration &cfg = config_->at(cameraStream->index);\n> +\t\tCameraStream *cameraStream = static_cast<CameraStream *>(stream->priv);\n> +\t\tStreamConfiguration &cfg = config_->at(cameraStream->index());\n>  \n>  \t\t/* Use the bufferCount confirmed by the validation process. */\n>  \t\tstream->max_buffers = cfg.bufferCount;\n> -\n> -\t\t/*\n> -\t\t * Construct a software encoder for MJPEG streams from the\n> -\t\t * chosen libcamera source stream.\n> -\t\t */\n> -\t\tif (cameraStream->format == formats::MJPEG) {\n> -\t\t\tcameraStream->jpeg = new EncoderLibJpeg();\n> -\t\t\tint ret = cameraStream->jpeg->configure(cfg);\n> -\t\t\tif (ret) {\n> -\t\t\t\tLOG(HAL, Error)\n> -\t\t\t\t\t<< \"Failed to configure encoder\";\n> -\t\t\t\treturn ret;\n> -\t\t\t}\n> -\t\t}\n>  \t}\n>  \n>  \t/*\n> @@ -1423,7 +1424,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n>  \t\t}\n>  \t\tdescriptor->frameBuffers.emplace_back(buffer);\n>  \n> -\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index);\n> +\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index());\n>  \t\tStream *stream = streamConfiguration->stream();\n>  \n>  \t\trequest->addBuffer(stream, buffer);\n> @@ -1478,7 +1479,7 @@ void CameraDevice::requestComplete(Request *request)\n>  \t\t\tcontinue;\n>  \t\t}\n>  \n> -\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index);\n> +\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index());\n>  \t\tStream *stream = streamConfiguration->stream();\n>  \t\tFrameBuffer *buffer = request->findBuffer(stream);\n>  \t\tif (!buffer) {\n> diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> index dc0ee664d443..f8f237203ce9 100644\n> --- a/src/android/camera_device.h\n> +++ b/src/android/camera_device.h\n> @@ -28,20 +28,24 @@\n>  class CameraMetadata;\n>  \n>  struct CameraStream {\n> -\tCameraStream(libcamera::PixelFormat, libcamera::Size);\n> +public:\n> +\tCameraStream(libcamera::PixelFormat, libcamera::Size, unsigned int i);\n>  \t~CameraStream();\n>  \n> -\t/*\n> -\t * The index of the libcamera StreamConfiguration as added during\n> -\t * configureStreams(). A single libcamera Stream may be used to deliver\n> -\t * one or more streams to the Android framework.\n> -\t */\n> -\tunsigned int index;\n> +\tunsigned int index() const { return index_; }\n>  \n>  \tlibcamera::PixelFormat format;\n>  \tlibcamera::Size size;\n>  \n>  \tEncoder *jpeg;\n> +\n> +private:\n> +\t/*\n> +\t * The index of the libcamera StreamConfiguration as added during\n> +\t * configureStreams(). A single libcamera Stream may be used to deliver\n> +\t * one or more streams to the Android framework.\n> +\t */\n> +\tunsigned int index_;\n>  };\n>  \n>  class CameraDevice : protected libcamera::Loggable\n> -- \n> 2.28.0\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","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 1DA01C3B5B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 10 Sep 2020 11:00:10 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9B69462D81;\n\tThu, 10 Sep 2020 13:00:09 +0200 (CEST)","from mail-lj1-x243.google.com (mail-lj1-x243.google.com\n\t[IPv6:2a00:1450:4864:20::243])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8F59262D27\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 10 Sep 2020 13:00:08 +0200 (CEST)","by mail-lj1-x243.google.com with SMTP id u21so7569777ljl.6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 10 Sep 2020 04:00:08 -0700 (PDT)","from localhost (h-209-203.A463.priv.bahnhof.se. [155.4.209.203])\n\tby smtp.gmail.com with ESMTPSA id\n\tf23sm1490129ljc.5.2020.09.10.04.00.07\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 10 Sep 2020 04:00:07 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=ragnatech-se.20150623.gappssmtp.com\n\theader.i=@ragnatech-se.20150623.gappssmtp.com\n\theader.b=\"jj1fdY+9\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=ragnatech-se.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:content-transfer-encoding:in-reply-to;\n\tbh=TfiWldd4+rqGUhhGwM9xNmpvdiLkgYnhOMcJ9dhDlc0=;\n\tb=jj1fdY+9rnap6P2cxtWmWocKUlgh2CycdDBPBJnEkUmY0NuKVo2jG0CdGtLVdU40sv\n\tRzXdm3JRG4mDpPElaBe8iC1OZRznsdT2R4/t3UsbYDJt+n52jjPZEnFFZpBPjSpgOL+1\n\tAO1Ps4dnRMUUHDZEuTA3IYbYyo3eFmsj14y006QAGZlU3Fgk2W/M8sSy6PvDQdqdFwLU\n\tlhRWKPk7pIWeXBnpQ/GDYvcQ3QAgRcwi4Il4tup2pR76Qx/3iA4Sx8y+iB4I0YnQEeK0\n\tODC7aVI0LWyEuuWcJH4jgZAiATTaYcG5vCuGAVkHpjCtSgaFyOoF25KWCWtdegrsr1nP\n\tl2TA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:content-transfer-encoding\n\t:in-reply-to;\n\tbh=TfiWldd4+rqGUhhGwM9xNmpvdiLkgYnhOMcJ9dhDlc0=;\n\tb=MDIY74IaKezjXJ07wzOSuHbMyy6VcJt78vkNcKYTvmMb1GSDkL972zMCgpwmn6iKqm\n\t7MDPCIVopaegBGJKSob3Al6/hl/vXQqM6h3AxvbdD1uFRx+AWKThZ3uNlsgSRHCFs1ze\n\tkcg6XaBrGpIjeDU4Xv5kjbwnHDJxru6MWSGTtdbj9M+o9grVjv6nKu/y3wNjiyr3Syke\n\tjXB0EsqMS3BrLeZWjfbmtTWG4M8gb1iJZVmQpu5VLQ6494BA8uRHP3KLnkBHvQQo2oQi\n\tfPfG8iomW7dIKUuHf7zS8rTQag/2QHckkTK2ukg97hakHMDu2ITwchiozaGb8WvQLvut\n\tVNrQ==","X-Gm-Message-State":"AOAM530nH+H5DvuX3sAqSxsMrPBSlZAsaVDB7DGjNzGaRcwioBRXqyYz\n\tB0zLPHpHFkUdEO+y/pDQ4jqIoA==","X-Google-Smtp-Source":"ABdhPJwyuu6YEKP1erSlEcWjtWGMW2Vd6hqTjUb6wJKwttIWKtByZKI74m6RjsmqqaRzwLQVvzrJ5Q==","X-Received":"by 2002:a2e:8983:: with SMTP id c3mr4300084lji.171.1599735607849;\n\tThu, 10 Sep 2020 04:00:07 -0700 (PDT)","Date":"Thu, 10 Sep 2020 13:00:06 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<20200910110006.GK4095624@oden.dyn.berto.se>","References":"<20200908134142.27470-1-jacopo@jmondi.org>\n\t<20200908134142.27470-10-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20200908134142.27470-10-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v3 09/11] android: camera_device:\n\tRework CameraStream handling","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>","Cc":"hanlinchen@chromium.org, libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"iso-8859-1\"","Content-Transfer-Encoding":"quoted-printable","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":12416,"web_url":"https://patchwork.libcamera.org/comment/12416/","msgid":"<20200910111509.axldxicvjdecbqxz@uno.localdomain>","date":"2020-09-10T11:15:09","subject":"Re: [libcamera-devel] [PATCH v3 09/11] android: camera_device:\n\tRework CameraStream handling","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Niklas,\n\nOn Thu, Sep 10, 2020 at 01:00:06PM +0200, Niklas Söderlund wrote:\n> Hi Jacopo,\n>\n> Thanks for your work.\n>\n> On 2020-09-08 15:41:40 +0200, Jacopo Mondi wrote:\n> > The CameraDevice::streams_ vector of CameraStream instances is\n> > currently mostly accessed by index. The current implementation\n> > creates all the CameraStream during the first loop that inspects the\n> > camera3_stream instances, and the update the index of the\n> > StreamConfiguration associated with the CameraStream during a second\n> > loop that inspects MJPEG streams. A third loop creates the JPEG encoder\n> > associated with CameraStreams that produce MJPEG format.\n> >\n> > As the index-based association is hard to follow and rather fragile,\n> > rework the creation and handling of CameraStream:\n> >\n> > 1) Make the StreamConfiguration index a constructor parameter and a\n> >    private struct member.  This disallow the creation of CameraStream\n> >    without a StreamConfiguration index assigned.\n> >\n> > 2) Create CameraStream only after the associated StreamConfiguration\n> >    has been identified. The first loop creates CameraStream for non-JPEG\n> >    streams, the second for the JPEG ones after having identified the\n> >    associated StreamConfiguration. Since we have just created the\n> >    CameraStream, create the JPEG encoder at the same time instead of\n> >    deferring it.\n> >\n> > This change removes all accesses by index to the CameraDevice::streams_\n> > vector.\n> >\n> > No functional changes intended, but this change aims to make the code\n> > easier to follow and more robust.\n> >\n> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > ---\n> >  src/android/camera_device.cpp | 91 ++++++++++++++++++-----------------\n> >  src/android/camera_device.h   | 18 ++++---\n> >  2 files changed, 57 insertions(+), 52 deletions(-)\n> >\n> > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> > index eab01d808917..e0260c92246c 100644\n> > --- a/src/android/camera_device.cpp\n> > +++ b/src/android/camera_device.cpp\n> > @@ -168,8 +168,8 @@ MappedCamera3Buffer::MappedCamera3Buffer(const buffer_handle_t camera3buffer,\n> >  \t}\n> >  }\n> >\n> > -CameraStream::CameraStream(PixelFormat f, Size s)\n> > -\t: index(-1), format(f), size(s), jpeg(nullptr)\n> > +CameraStream::CameraStream(PixelFormat f, Size s, unsigned int i)\n> > +\t: format(f), size(s), jpeg(nullptr), index_(i)\n> >  {\n> >  }\n> >\n> > @@ -1190,6 +1190,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> >  \tstreams_.reserve(stream_list->num_streams);\n> >\n> >  \t/* First handle all non-MJPEG streams. */\n> > +\tcamera3_stream_t *jpegStream = nullptr;\n> >  \tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> >  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n> >  \t\tSize size(stream->width, stream->height);\n> > @@ -1206,52 +1207,50 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> >  \t\tif (!format.isValid())\n> >  \t\t\treturn -EINVAL;\n> >\n> > -\t\tstreams_.emplace_back(format, size);\n> > -\t\tstream->priv = static_cast<void *>(&streams_[i]);\n> > -\n> >  \t\t/* Defer handling of MJPEG streams until all others are known. */\n> > -\t\tif (stream->format == HAL_PIXEL_FORMAT_BLOB)\n> > +\t\tif (stream->format == HAL_PIXEL_FORMAT_BLOB) {\n> > +\t\t\tjpegStream = stream;\n> >  \t\t\tcontinue;\n> > +\t\t}\n> >\n> >  \t\tStreamConfiguration streamConfiguration;\n> > -\n> >  \t\tstreamConfiguration.size = size;\n> >  \t\tstreamConfiguration.pixelFormat = format;\n> >\n> >  \t\tconfig_->addConfiguration(streamConfiguration);\n> > -\t\tstreams_[i].index = config_->size() - 1;\n> > +\t\tunsigned int index = config_->size() - 1;\n> > +\t\tstreams_.emplace_back(format, size, index);\n> > +\t\tstream->priv = static_cast<void *>(&streams_.back());\n>\n> Is this not dangerous? If the stremas_ vector is modified in any way the\n> members may be reallocated and the pointer becomes invalid. I think this\n> is what boost::container::stable_vector tries to solve for example.\n\nWe reserve space for all possible entries in advance to avoid\nrelocations.\n\n>\n> >  \t}\n> >\n> >  \t/* Now handle MJPEG streams, adding a new stream if required. */\n> > -\tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> > -\t\tcamera3_stream_t *stream = stream_list->streams[i];\n> > -\t\tbool match = false;\n> > -\n> > -\t\tif (stream->format != HAL_PIXEL_FORMAT_BLOB)\n> > -\t\t\tcontinue;\n> > +\tif (jpegStream) {\n> > +\t\tint index = -1;\n> >\n> > -\t\t/* Search for a compatible stream */\n> > -\t\tfor (unsigned int j = 0; j < config_->size(); j++) {\n> > -\t\t\tStreamConfiguration &cfg = config_->at(j);\n> > +\t\t/* Search for a compatible stream in the non-JPEG ones. */\n> > +\t\tfor (unsigned int i = 0; i < config_->size(); i++) {\n> > +\t\t\tStreamConfiguration &cfg = config_->at(i);\n> >\n> >  \t\t\t/*\n> >  \t\t\t * \\todo The PixelFormat must also be compatible with\n> >  \t\t\t * the encoder.\n> >  \t\t\t */\n> > -\t\t\tif (cfg.size == streams_[i].size) {\n> > -\t\t\t\tLOG(HAL, Info) << \"Stream \" << i\n> > -\t\t\t\t\t       << \" using libcamera stream \" << j;\n> > +\t\t\tif (cfg.size.width != jpegStream->width ||\n> > +\t\t\t    cfg.size.height != jpegStream->height)\n> > +\t\t\t\tcontinue;\n> >\n> > -\t\t\t\tmatch = true;\n> > -\t\t\t\tstreams_[i].index = j;\n> > -\t\t\t}\n> > +\t\t\tLOG(HAL, Info)\n> > +\t\t\t\t<< \"Android JPEG stream mapped on stream \" << i;\n> > +\n> > +\t\t\tindex = i;\n> > +\t\t\tbreak;\n> >  \t\t}\n> >\n> >  \t\t/*\n> >  \t\t * Without a compatible match for JPEG encoding we must\n> >  \t\t * introduce a new stream to satisfy the request requirements.\n> >  \t\t */\n> > -\t\tif (!match) {\n> > +\t\tif (index < 0) {\n> >  \t\t\tStreamConfiguration streamConfiguration;\n> >\n> >  \t\t\t/*\n> > @@ -1260,15 +1259,31 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> >  \t\t\t * handled, and should be considered as part of any\n> >  \t\t\t * stream configuration reworks.\n> >  \t\t\t */\n> > -\t\t\tstreamConfiguration.size.width = stream->width;\n> > -\t\t\tstreamConfiguration.size.height = stream->height;\n> > +\t\t\tstreamConfiguration.size.width = jpegStream->width;\n> > +\t\t\tstreamConfiguration.size.height = jpegStream->height;\n> >  \t\t\tstreamConfiguration.pixelFormat = formats::NV12;\n> >\n> >  \t\t\tLOG(HAL, Info) << \"Adding \" << streamConfiguration.toString()\n> >  \t\t\t\t       << \" for MJPEG support\";\n> >\n> >  \t\t\tconfig_->addConfiguration(streamConfiguration);\n> > -\t\t\tstreams_[i].index = config_->size() - 1;\n> > +\t\t\tindex = config_->size() - 1;\n> > +\t\t}\n> > +\n> > +\t\tStreamConfiguration &cfg = config_->at(index);\n> > +\t\tCameraStream &cameraStream =\n> > +\t\t\tstreams_.emplace_back(formats::MJPEG, cfg.size, index);\n> > +\t\tjpegStream->priv = static_cast<void *>(&cameraStream);\n> > +\n> > +\t\t/*\n> > +\t\t * Construct a software encoder for MJPEG streams from the\n> > +\t\t * chosen libcamera source stream.\n> > +\t\t */\n> > +\t\tcameraStream.jpeg = new EncoderLibJpeg();\n> > +\t\tint ret = cameraStream.jpeg->configure(cfg);\n> > +\t\tif (ret) {\n> > +\t\t\tLOG(HAL, Error) << \"Failed to configure encoder\";\n> > +\t\t\treturn ret;\n> >  \t\t}\n> >  \t}\n> >\n> > @@ -1291,25 +1306,11 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> >\n> >  \tfor (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> >  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n> > -\t\tCameraStream *cameraStream = &streams_[i];\n> > -\t\tStreamConfiguration &cfg = config_->at(cameraStream->index);\n> > +\t\tCameraStream *cameraStream = static_cast<CameraStream *>(stream->priv);\n> > +\t\tStreamConfiguration &cfg = config_->at(cameraStream->index());\n> >\n> >  \t\t/* Use the bufferCount confirmed by the validation process. */\n> >  \t\tstream->max_buffers = cfg.bufferCount;\n> > -\n> > -\t\t/*\n> > -\t\t * Construct a software encoder for MJPEG streams from the\n> > -\t\t * chosen libcamera source stream.\n> > -\t\t */\n> > -\t\tif (cameraStream->format == formats::MJPEG) {\n> > -\t\t\tcameraStream->jpeg = new EncoderLibJpeg();\n> > -\t\t\tint ret = cameraStream->jpeg->configure(cfg);\n> > -\t\t\tif (ret) {\n> > -\t\t\t\tLOG(HAL, Error)\n> > -\t\t\t\t\t<< \"Failed to configure encoder\";\n> > -\t\t\t\treturn ret;\n> > -\t\t\t}\n> > -\t\t}\n> >  \t}\n> >\n> >  \t/*\n> > @@ -1423,7 +1424,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> >  \t\t}\n> >  \t\tdescriptor->frameBuffers.emplace_back(buffer);\n> >\n> > -\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index);\n> > +\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index());\n> >  \t\tStream *stream = streamConfiguration->stream();\n> >\n> >  \t\trequest->addBuffer(stream, buffer);\n> > @@ -1478,7 +1479,7 @@ void CameraDevice::requestComplete(Request *request)\n> >  \t\t\tcontinue;\n> >  \t\t}\n> >\n> > -\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index);\n> > +\t\tStreamConfiguration *streamConfiguration = &config_->at(cameraStream->index());\n> >  \t\tStream *stream = streamConfiguration->stream();\n> >  \t\tFrameBuffer *buffer = request->findBuffer(stream);\n> >  \t\tif (!buffer) {\n> > diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> > index dc0ee664d443..f8f237203ce9 100644\n> > --- a/src/android/camera_device.h\n> > +++ b/src/android/camera_device.h\n> > @@ -28,20 +28,24 @@\n> >  class CameraMetadata;\n> >\n> >  struct CameraStream {\n> > -\tCameraStream(libcamera::PixelFormat, libcamera::Size);\n> > +public:\n> > +\tCameraStream(libcamera::PixelFormat, libcamera::Size, unsigned int i);\n> >  \t~CameraStream();\n> >\n> > -\t/*\n> > -\t * The index of the libcamera StreamConfiguration as added during\n> > -\t * configureStreams(). A single libcamera Stream may be used to deliver\n> > -\t * one or more streams to the Android framework.\n> > -\t */\n> > -\tunsigned int index;\n> > +\tunsigned int index() const { return index_; }\n> >\n> >  \tlibcamera::PixelFormat format;\n> >  \tlibcamera::Size size;\n> >\n> >  \tEncoder *jpeg;\n> > +\n> > +private:\n> > +\t/*\n> > +\t * The index of the libcamera StreamConfiguration as added during\n> > +\t * configureStreams(). A single libcamera Stream may be used to deliver\n> > +\t * one or more streams to the Android framework.\n> > +\t */\n> > +\tunsigned int index_;\n> >  };\n> >\n> >  class CameraDevice : protected libcamera::Loggable\n> > --\n> > 2.28.0\n> >\n> > _______________________________________________\n> > libcamera-devel mailing list\n> > libcamera-devel@lists.libcamera.org\n> > https://lists.libcamera.org/listinfo/libcamera-devel\n>\n> --\n> Regards,\n> Niklas Söderlund","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 65D56C3B5B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 10 Sep 2020 11:11:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 40B7B62D81;\n\tThu, 10 Sep 2020 13:11:22 +0200 (CEST)","from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n\t[217.70.183.201])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D2D1B62D04\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 10 Sep 2020 13:11:21 +0200 (CEST)","from uno.localdomain (93-34-118-233.ip49.fastwebnet.it\n\t[93.34.118.233]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay8-d.mail.gandi.net (Postfix) with ESMTPSA id 2C72D1BF203;\n\tThu, 10 Sep 2020 11:11:20 +0000 (UTC)"],"X-Originating-IP":"93.34.118.233","Date":"Thu, 10 Sep 2020 13:15:09 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Message-ID":"<20200910111509.axldxicvjdecbqxz@uno.localdomain>","References":"<20200908134142.27470-1-jacopo@jmondi.org>\n\t<20200908134142.27470-10-jacopo@jmondi.org>\n\t<20200910110006.GK4095624@oden.dyn.berto.se>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20200910110006.GK4095624@oden.dyn.berto.se>","Subject":"Re: [libcamera-devel] [PATCH v3 09/11] android: camera_device:\n\tRework CameraStream handling","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>","Cc":"hanlinchen@chromium.org, libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":12438,"web_url":"https://patchwork.libcamera.org/comment/12438/","msgid":"<CAO5uPHNPJnAp+zQv0C39thhAJfLH_8j5XfHR5LmLf-iAgY3eQg@mail.gmail.com>","date":"2020-09-11T02:39:52","subject":"Re: [libcamera-devel] [PATCH v3 09/11] android: camera_device:\n\tRework CameraStream handling","submitter":{"id":63,"url":"https://patchwork.libcamera.org/api/people/63/","name":"Hirokazu Honda","email":"hiroh@chromium.org"},"content":"Hi Jacopo, Thanks for the patch.\n\nOn Thu, Sep 10, 2020 at 8:11 PM Jacopo Mondi <jacopo@jmondi.org> wrote:\n>\n> Hi Niklas,\n>\n> On Thu, Sep 10, 2020 at 01:00:06PM +0200, Niklas Söderlund wrote:\n> > Hi Jacopo,\n> >\n> > Thanks for your work.\n> >\n> > On 2020-09-08 15:41:40 +0200, Jacopo Mondi wrote:\n> > > The CameraDevice::streams_ vector of CameraStream instances is\n> > > currently mostly accessed by index. The current implementation\n> > > creates all the CameraStream during the first loop that inspects the\n> > > camera3_stream instances, and the update the index of the\n> > > StreamConfiguration associated with the CameraStream during a second\n> > > loop that inspects MJPEG streams. A third loop creates the JPEG encoder\n> > > associated with CameraStreams that produce MJPEG format.\n> > >\n> > > As the index-based association is hard to follow and rather fragile,\n> > > rework the creation and handling of CameraStream:\n> > >\n> > > 1) Make the StreamConfiguration index a constructor parameter and a\n> > >    private struct member.  This disallow the creation of CameraStream\n> > >    without a StreamConfiguration index assigned.\n> > >\n> > > 2) Create CameraStream only after the associated StreamConfiguration\n> > >    has been identified. The first loop creates CameraStream for non-JPEG\n> > >    streams, the second for the JPEG ones after having identified the\n> > >    associated StreamConfiguration. Since we have just created the\n> > >    CameraStream, create the JPEG encoder at the same time instead of\n> > >    deferring it.\n> > >\n> > > This change removes all accesses by index to the CameraDevice::streams_\n> > > vector.\n> > >\n> > > No functional changes intended, but this change aims to make the code\n> > > easier to follow and more robust.\n> > >\n> > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n\nReviewed-by: Hirokazu Honda <hiroh@chromium.org>\n\n> > > ---\n> > >  src/android/camera_device.cpp | 91 ++++++++++++++++++-----------------\n> > >  src/android/camera_device.h   | 18 ++++---\n> > >  2 files changed, 57 insertions(+), 52 deletions(-)\n> > >\n> > > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> > > index eab01d808917..e0260c92246c 100644\n> > > --- a/src/android/camera_device.cpp\n> > > +++ b/src/android/camera_device.cpp\n> > > @@ -168,8 +168,8 @@ MappedCamera3Buffer::MappedCamera3Buffer(const buffer_handle_t camera3buffer,\n> > >     }\n> > >  }\n> > >\n> > > -CameraStream::CameraStream(PixelFormat f, Size s)\n> > > -   : index(-1), format(f), size(s), jpeg(nullptr)\n> > > +CameraStream::CameraStream(PixelFormat f, Size s, unsigned int i)\n> > > +   : format(f), size(s), jpeg(nullptr), index_(i)\n> > >  {\n> > >  }\n> > >\n> > > @@ -1190,6 +1190,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> > >     streams_.reserve(stream_list->num_streams);\n> > >\n> > >     /* First handle all non-MJPEG streams. */\n> > > +   camera3_stream_t *jpegStream = nullptr;\n> > >     for (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> > >             camera3_stream_t *stream = stream_list->streams[i];\n> > >             Size size(stream->width, stream->height);\n> > > @@ -1206,52 +1207,50 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> > >             if (!format.isValid())\n> > >                     return -EINVAL;\n> > >\n> > > -           streams_.emplace_back(format, size);\n> > > -           stream->priv = static_cast<void *>(&streams_[i]);\n> > > -\n> > >             /* Defer handling of MJPEG streams until all others are known. */\n> > > -           if (stream->format == HAL_PIXEL_FORMAT_BLOB)\n> > > +           if (stream->format == HAL_PIXEL_FORMAT_BLOB) {\n> > > +                   jpegStream = stream;\n> > >                     continue;\n> > > +           }\n> > >\n> > >             StreamConfiguration streamConfiguration;\n> > > -\n> > >             streamConfiguration.size = size;\n> > >             streamConfiguration.pixelFormat = format;\n> > >\n> > >             config_->addConfiguration(streamConfiguration);\n> > > -           streams_[i].index = config_->size() - 1;\n> > > +           unsigned int index = config_->size() - 1;\n> > > +           streams_.emplace_back(format, size, index);\n> > > +           stream->priv = static_cast<void *>(&streams_.back());\n> >\n> > Is this not dangerous? If the stremas_ vector is modified in any way the\n> > members may be reallocated and the pointer becomes invalid. I think this\n> > is what boost::container::stable_vector tries to solve for example.\n>\n> We reserve space for all possible entries in advance to avoid\n> relocations.\n>\n> >\n> > >     }\n> > >\n> > >     /* Now handle MJPEG streams, adding a new stream if required. */\n> > > -   for (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> > > -           camera3_stream_t *stream = stream_list->streams[i];\n> > > -           bool match = false;\n> > > -\n> > > -           if (stream->format != HAL_PIXEL_FORMAT_BLOB)\n> > > -                   continue;\n> > > +   if (jpegStream) {\n> > > +           int index = -1;\n> > >\n> > > -           /* Search for a compatible stream */\n> > > -           for (unsigned int j = 0; j < config_->size(); j++) {\n> > > -                   StreamConfiguration &cfg = config_->at(j);\n> > > +           /* Search for a compatible stream in the non-JPEG ones. */\n> > > +           for (unsigned int i = 0; i < config_->size(); i++) {\n> > > +                   StreamConfiguration &cfg = config_->at(i);\n> > >\n> > >                     /*\n> > >                      * \\todo The PixelFormat must also be compatible with\n> > >                      * the encoder.\n> > >                      */\n> > > -                   if (cfg.size == streams_[i].size) {\n> > > -                           LOG(HAL, Info) << \"Stream \" << i\n> > > -                                          << \" using libcamera stream \" << j;\n> > > +                   if (cfg.size.width != jpegStream->width ||\n> > > +                       cfg.size.height != jpegStream->height)\n> > > +                           continue;\n> > >\n> > > -                           match = true;\n> > > -                           streams_[i].index = j;\n> > > -                   }\n> > > +                   LOG(HAL, Info)\n> > > +                           << \"Android JPEG stream mapped on stream \" << i;\n> > > +\n> > > +                   index = i;\n> > > +                   break;\n> > >             }\n> > >\n> > >             /*\n> > >              * Without a compatible match for JPEG encoding we must\n> > >              * introduce a new stream to satisfy the request requirements.\n> > >              */\n> > > -           if (!match) {\n> > > +           if (index < 0) {\n> > >                     StreamConfiguration streamConfiguration;\n> > >\n> > >                     /*\n> > > @@ -1260,15 +1259,31 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> > >                      * handled, and should be considered as part of any\n> > >                      * stream configuration reworks.\n> > >                      */\n> > > -                   streamConfiguration.size.width = stream->width;\n> > > -                   streamConfiguration.size.height = stream->height;\n> > > +                   streamConfiguration.size.width = jpegStream->width;\n> > > +                   streamConfiguration.size.height = jpegStream->height;\n> > >                     streamConfiguration.pixelFormat = formats::NV12;\n> > >\n> > >                     LOG(HAL, Info) << \"Adding \" << streamConfiguration.toString()\n> > >                                    << \" for MJPEG support\";\n> > >\n> > >                     config_->addConfiguration(streamConfiguration);\n> > > -                   streams_[i].index = config_->size() - 1;\n> > > +                   index = config_->size() - 1;\n> > > +           }\n> > > +\n> > > +           StreamConfiguration &cfg = config_->at(index);\n> > > +           CameraStream &cameraStream =\n> > > +                   streams_.emplace_back(formats::MJPEG, cfg.size, index);\n> > > +           jpegStream->priv = static_cast<void *>(&cameraStream);\n> > > +\n> > > +           /*\n> > > +            * Construct a software encoder for MJPEG streams from the\n> > > +            * chosen libcamera source stream.\n> > > +            */\n> > > +           cameraStream.jpeg = new EncoderLibJpeg();\n> > > +           int ret = cameraStream.jpeg->configure(cfg);\n> > > +           if (ret) {\n> > > +                   LOG(HAL, Error) << \"Failed to configure encoder\";\n> > > +                   return ret;\n> > >             }\n> > >     }\n> > >\n> > > @@ -1291,25 +1306,11 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> > >\n> > >     for (unsigned int i = 0; i < stream_list->num_streams; ++i) {\n> > >             camera3_stream_t *stream = stream_list->streams[i];\n> > > -           CameraStream *cameraStream = &streams_[i];\n> > > -           StreamConfiguration &cfg = config_->at(cameraStream->index);\n> > > +           CameraStream *cameraStream = static_cast<CameraStream *>(stream->priv);\n> > > +           StreamConfiguration &cfg = config_->at(cameraStream->index());\n> > >\n> > >             /* Use the bufferCount confirmed by the validation process. */\n> > >             stream->max_buffers = cfg.bufferCount;\n> > > -\n> > > -           /*\n> > > -            * Construct a software encoder for MJPEG streams from the\n> > > -            * chosen libcamera source stream.\n> > > -            */\n> > > -           if (cameraStream->format == formats::MJPEG) {\n> > > -                   cameraStream->jpeg = new EncoderLibJpeg();\n> > > -                   int ret = cameraStream->jpeg->configure(cfg);\n> > > -                   if (ret) {\n> > > -                           LOG(HAL, Error)\n> > > -                                   << \"Failed to configure encoder\";\n> > > -                           return ret;\n> > > -                   }\n> > > -           }\n> > >     }\n> > >\n> > >     /*\n> > > @@ -1423,7 +1424,7 @@ int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Reques\n> > >             }\n> > >             descriptor->frameBuffers.emplace_back(buffer);\n> > >\n> > > -           StreamConfiguration *streamConfiguration = &config_->at(cameraStream->index);\n> > > +           StreamConfiguration *streamConfiguration = &config_->at(cameraStream->index());\n> > >             Stream *stream = streamConfiguration->stream();\n> > >\n> > >             request->addBuffer(stream, buffer);\n> > > @@ -1478,7 +1479,7 @@ void CameraDevice::requestComplete(Request *request)\n> > >                     continue;\n> > >             }\n> > >\n> > > -           StreamConfiguration *streamConfiguration = &config_->at(cameraStream->index);\n> > > +           StreamConfiguration *streamConfiguration = &config_->at(cameraStream->index());\n> > >             Stream *stream = streamConfiguration->stream();\n> > >             FrameBuffer *buffer = request->findBuffer(stream);\n> > >             if (!buffer) {\n> > > diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> > > index dc0ee664d443..f8f237203ce9 100644\n> > > --- a/src/android/camera_device.h\n> > > +++ b/src/android/camera_device.h\n> > > @@ -28,20 +28,24 @@\n> > >  class CameraMetadata;\n> > >\n> > >  struct CameraStream {\n> > > -   CameraStream(libcamera::PixelFormat, libcamera::Size);\n> > > +public:\n> > > +   CameraStream(libcamera::PixelFormat, libcamera::Size, unsigned int i);\n> > >     ~CameraStream();\n> > >\n> > > -   /*\n> > > -    * The index of the libcamera StreamConfiguration as added during\n> > > -    * configureStreams(). A single libcamera Stream may be used to deliver\n> > > -    * one or more streams to the Android framework.\n> > > -    */\n> > > -   unsigned int index;\n> > > +   unsigned int index() const { return index_; }\n> > >\n> > >     libcamera::PixelFormat format;\n> > >     libcamera::Size size;\n> > >\n> > >     Encoder *jpeg;\n> > > +\n> > > +private:\n> > > +   /*\n> > > +    * The index of the libcamera StreamConfiguration as added during\n> > > +    * configureStreams(). A single libcamera Stream may be used to deliver\n> > > +    * one or more streams to the Android framework.\n> > > +    */\n> > > +   unsigned int index_;\n> > >  };\n> > >\n> > >  class CameraDevice : protected libcamera::Loggable\n> > > --\n> > > 2.28.0\n> > >\n> > > _______________________________________________\n> > > libcamera-devel mailing list\n> > > libcamera-devel@lists.libcamera.org\n> > > https://lists.libcamera.org/listinfo/libcamera-devel\n> >\n> > --\n> > Regards,\n> > Niklas Söderlund\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","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 74621C3B5B\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 11 Sep 2020 02:40:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F14FB62D4B;\n\tFri, 11 Sep 2020 04:40:04 +0200 (CEST)","from mail-ed1-x542.google.com (mail-ed1-x542.google.com\n\t[IPv6:2a00:1450:4864:20::542])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1C29E6037B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 11 Sep 2020 04:40:03 +0200 (CEST)","by mail-ed1-x542.google.com with SMTP id n13so8373302edo.10\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 10 Sep 2020 19:40:03 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"JcsClanq\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org;\n\ts=google; \n\th=mime-version:references:in-reply-to:from:date:message-id:subject:to\n\t:cc:content-transfer-encoding;\n\tbh=OtGJ40G58GcDGWZKrQgPljD4Tq+AdWfRqmzGuNq0y0Y=;\n\tb=JcsClanqVDu9Pc3Cmq/cT/DqbjFS1XO52kqYQ8kZCsqNhev6EN3pBBCJvOLs2AFwoR\n\tMVdOECxV4EKQNZFxDrfWL9Qf0vTdeNqARCNGDSb1IIflelLdREOcgoISktKBH4Adh7Yz\n\tBYgKq6K/SBHAUMsXKNO5lMpR+29C9UOxWKf60=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:references:in-reply-to:from:date\n\t:message-id:subject:to:cc:content-transfer-encoding;\n\tbh=OtGJ40G58GcDGWZKrQgPljD4Tq+AdWfRqmzGuNq0y0Y=;\n\tb=Ategf96pqA8oNZJlsCD+cF+LeNNXtfWhx8ntynYTRCUG9qVKjnUsXKX6etR0CYu3zB\n\tqO6Zlz/a+8wWxaf4A6jNven6ebJR9ArvQ9cl7SUlXob4ZXMYfktMpn4uJ02fjIe0G4Xn\n\tvSFBjQjUKULtYQEXwU3bW0JhFCWVmB0aHvV7x4JgdwewqTi8iEU7Ia21gDgaq9U5NC7V\n\tSOmylbVouIb/DZ1MwYzYXLN3qVgrkwwzdQC0flv+fcE+0gxRUw7jpB52+4tuMKDozhet\n\toWUrMEo7Q+q34/DYmZtojXBkIIK42sUkjLCvQe2k0hX5T59IhcgKxz1ODF5ouJv56ILi\n\tjVOQ==","X-Gm-Message-State":"AOAM530mO/Ag+0jPd3jcSmG8N6ChTn8ZOOVZk7Ta3dxCZmkWyXaE4V6b\n\tE5CVWXmx31WRvZGA6ggpEX2/aeNEDGXr4imLGtnyTPO/Hr8=","X-Google-Smtp-Source":"ABdhPJwf17gslGWV7kh6LaQ7cD0v005NSUTxsGDt7Kj6iZN8bbmvrNL104YznbTXlaclg2Gkb0SR+3VHsCc665P56H4=","X-Received":"by 2002:a05:6402:3192:: with SMTP id\n\tdi18mr12638788edb.116.1599792002632; \n\tThu, 10 Sep 2020 19:40:02 -0700 (PDT)","MIME-Version":"1.0","References":"<20200908134142.27470-1-jacopo@jmondi.org>\n\t<20200908134142.27470-10-jacopo@jmondi.org>\n\t<20200910110006.GK4095624@oden.dyn.berto.se>\n\t<20200910111509.axldxicvjdecbqxz@uno.localdomain>","In-Reply-To":"<20200910111509.axldxicvjdecbqxz@uno.localdomain>","From":"Hirokazu Honda <hiroh@chromium.org>","Date":"Fri, 11 Sep 2020 11:39:52 +0900","Message-ID":"<CAO5uPHNPJnAp+zQv0C39thhAJfLH_8j5XfHR5LmLf-iAgY3eQg@mail.gmail.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [PATCH v3 09/11] android: camera_device:\n\tRework CameraStream handling","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>","Cc":"Hanlin Chen <hanlinchen@chromium.org>,\n\tlibcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]