[{"id":11428,"web_url":"https://patchwork.libcamera.org/comment/11428/","msgid":"<20200718154159.GA571076@oden.dyn.berto.se>","date":"2020-07-18T15:41:59","subject":"Re: [libcamera-devel] [PATCH v3 08/10] libcamera: pipeline:\n\traspberrypi: Add more robust stream buffer logic","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Naushir,\n\nThanks for your work,\n\nOn 2020-07-17 09:54:08 +0100, Naushir Patuck wrote:\n> Add further queueing into the RPiStream object to ensure that we always\n> follow the buffer ordering (be it internal or external) given by\n> incoming Requests.\n> \n> This is essential, otherwise we risk dropping frames that are meant to\n> be part of a Request, and can cause the pipeline to stall indefinitely.\n> This also prevents any possibility of mismatched frame buffers going\n> through the pipeline and out to the application.\n> \n> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>\n> ---\n>  .../pipeline/raspberrypi/rpi_stream.cpp       | 73 ++++++++++++++++---\n>  .../pipeline/raspberrypi/rpi_stream.h         | 12 ++-\n>  2 files changed, 73 insertions(+), 12 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp\n> index 53a335e3..4818117e 100644\n> --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp\n> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp\n> @@ -112,25 +112,34 @@ int RPiStream::queueBuffer(FrameBuffer *buffer)\n>  \t */\n>  \tif (!buffer) {\n>  \t\tif (availableBuffers_.empty()) {\n> -\t\t\tLOG(RPISTREAM, Warning) << \"No buffers available for \"\n> +\t\t\tLOG(RPISTREAM, Info) << \"No buffers available for \"\n>  \t\t\t\t\t\t<< name_;\n> -\t\t\treturn -EINVAL;\n> +\t\t\t/*\n> +\t\t\t * Note that we need to requeue an internal buffer as soon\n> +\t\t\t * as one becomes available.\n> +\t\t\t */\n> +\t\t\trequeueBuffers_.push(nullptr);\n> +\t\t\treturn 0;\n>  \t\t}\n>  \n>  \t\tbuffer = availableBuffers_.front();\n>  \t\tavailableBuffers_.pop();\n>  \t}\n>  \n> -\tLOG(RPISTREAM, Debug) << \"Queuing buffer \" << buffer->cookie()\n> -\t\t\t      << \" for \" << name_;\n> -\n> -\tint ret = dev_->queueBuffer(buffer);\n> -\tif (ret) {\n> -\t\tLOG(RPISTREAM, Error) << \"Failed to queue buffer for \"\n> -\t\t\t\t      << name_;\n> +\tif (requeueBuffers_.empty()) {\n> +\t\t/*\n> +\t\t * No earlier requests are pending to be queued, so we can\n> +\t\t * go ahead and queue the buffer into the device.\n> +\t\t */\n> +\t\treturn queueToDevice(buffer);\n> +\t} else {\n> +\t\t/*\n> +\t\t * There are earlier buffers to be queued, so this buffer\n> +\t\t * must go on the waiting list.\n> +\t\t */\n> +\t\trequeueBuffers_.push(buffer);\n> +\t\treturn 0;\n>  \t}\n\nThis could possibly be made easier to read,\n\n    /*\n     * If no earlier requests are pending to be queued we can\n     * go ahead and queue the buffer into the device.\n     /\n    if (requeueBuffers_.empty())\n        return queueToDevice(buffer);\n\n    /*\n     * There are earlier buffers to be queued, so this buffer\n     * must go on the waiting list.\n     */\n    requeueBuffers_.push(buffer);\n\n    return 0;\n\n> -\n> -\treturn ret;\n>  }\n>  \n>  void RPiStream::returnBuffer(FrameBuffer *buffer)\n> @@ -138,7 +147,36 @@ void RPiStream::returnBuffer(FrameBuffer *buffer)\n>  \t/* This can only be called for external streams. */\n>  \tassert(external_);\n>  \n> +\t/* Push this buffer back into the queue to be used again. */\n>  \tavailableBuffers_.push(buffer);\n> +\n> +\t/*\n> +\t * Do we have any buffers that are waiting to be queued?\n> +\t * If so, do it now as availableBuffers_ will not be empty.\n> +\t */\n> +\twhile (!requeueBuffers_.empty()) {\n> +\t\tFrameBuffer *buffer = requeueBuffers_.front();\n> +\n> +\t\tif (!buffer && availableBuffers_.empty()) {\n> +\t\t\t/*\n> +\t\t\t * We want to queue an internal buffer, but none\n> +\t\t\t * are available. Can't do anything, quit the loop.\n> +\t\t\t */\n> +\t\t\tbreak;\n> +\t\t}\n> +\n> +\t\tif (!buffer) {\n> +\t\t\t/*\n> +\t\t\t * We want to queue an internal buffer, and at least one\n> +\t\t\t * is available.\n> +\t\t\t */\n> +\t\t\tbuffer = availableBuffers_.front();\n> +\t\t\tavailableBuffers_.pop();\n> +\t\t}\n\nAlso this could be made easier to read.\n\n    if (!buffer) {\n        /*\n         * We want to queue an internal buffer, but none\n         * are available. Can't do anything, quit the loop.\n         */\n        if (availableBuffers_.empty())\n            break;\n\n        /*\n         * We want to queue an internal buffer, and at least one\n         * is available.\n         */\n        buffer = availableBuffers_.front();\n        availableBuffers_.pop();\n    }\n\nBoth my comments are nit on styler so with or without them addressed,\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> +\n> +\t\trequeueBuffers_.pop();\n> +\t\tqueueToDevice(buffer);\n> +\t}\n>  }\n>  \n>  bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const\n> @@ -155,10 +193,23 @@ bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const\n>  void RPiStream::clearBuffers()\n>  {\n>  \tavailableBuffers_ = std::queue<FrameBuffer *>{};\n> +\trequeueBuffers_ = std::queue<FrameBuffer *>{};\n>  \tinternalBuffers_.clear();\n>  \tbufferList_.clear();\n>  }\n>  \n> +int RPiStream::queueToDevice(FrameBuffer *buffer)\n> +{\n> +\tLOG(RPISTREAM, Debug) << \"Queuing buffer \" << buffer->cookie()\n> +\t\t\t      << \" for \" << name_;\n> +\n> +\tint ret = dev_->queueBuffer(buffer);\n> +\tif (ret)\n> +\t\tLOG(RPISTREAM, Error) << \"Failed to queue buffer for \"\n> +\t\t\t\t      << name_;\n> +\treturn ret;\n> +}\n> +\n>  } /* namespace RPi */\n>  \n>  } /* namespace libcamera */\n> diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h\n> index 019e236d..6c8dfa83 100644\n> --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h\n> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h\n> @@ -51,6 +51,7 @@ public:\n>  \n>  private:\n>  \tvoid clearBuffers();\n> +\tint queueToDevice(FrameBuffer *buffer);\n>  \t/*\n>  \t * Indicates that this stream is active externally, i.e. the buffers\n>  \t * might be provided by (and returned to) the application.\n> @@ -62,7 +63,7 @@ private:\n>  \tstd::string name_;\n>  \t/* The actual device stream. */\n>  \tstd::unique_ptr<V4L2VideoDevice> dev_;\n> -\t/* All framebuffers associated with this device stream. */\n> +\t/* All frame buffers associated with this device stream. */\n>  \tstd::vector<FrameBuffer *> bufferList_;\n>  \t/*\n>  \t * List of frame buffer that we can use if none have been provided by\n> @@ -70,6 +71,15 @@ private:\n>  \t * buffers exported internally.\n>  \t */\n>  \tstd::queue<FrameBuffer *> availableBuffers_;\n> +\t/*\n> +\t * List of frame buffer that are to be re-queued into the device.\n> +\t * A nullptr indicates any internal buffer can be used (from availableBuffers_),\n> +\t * whereas a valid pointer indicates an external buffer to be queued.\n> +\t *\n> +\t * Ordering buffers to be queued is important here as it must match the\n> +\t * requests coming from the application.\n> +\t */\n> +\tstd::queue<FrameBuffer *> requeueBuffers_;\n>  \t/*\n>  \t * This is a list of buffers exported internally. Need to keep this around\n>  \t * as the stream needs to maintain ownership of these buffers.\n> -- \n> 2.25.1\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 A32B1C0109\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 18 Jul 2020 15:42:02 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 3010260589;\n\tSat, 18 Jul 2020 17:42:02 +0200 (CEST)","from mail-lf1-x142.google.com (mail-lf1-x142.google.com\n\t[IPv6:2a00:1450:4864:20::142])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2FC7160493\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 18 Jul 2020 17:42:01 +0200 (CEST)","by mail-lf1-x142.google.com with SMTP id u25so7641409lfm.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 18 Jul 2020 08:42:01 -0700 (PDT)","from localhost (h-209-203.A463.priv.bahnhof.se. [155.4.209.203])\n\tby smtp.gmail.com with ESMTPSA id\n\tr19sm2263974ljm.32.2020.07.18.08.41.59\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tSat, 18 Jul 2020 08:41:59 -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=\"nDDZEvPR\"; 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=S07dqOrAPYr6OhIdWBbRcmQQlcCzUS9aY7GNFfNZiek=;\n\tb=nDDZEvPRkg/DvAek/6dsm7XJ93IjkC3nTAWJ4rx0ozayZZWQWTBKR5BRtdTdOyV+MN\n\tDnRTKunVJP14sTWpyXWXwW2eVPpmWXCGTC2wp/WJC0Sm9TdfcfHLA9jGWLX9T3u60Ag9\n\t1nud7lXOm9vJdujREbBgvECB6cNQp8C+brqMg6ikoGoZwBQplJiaElhUQDC2kG/BwI2C\n\tVgSrONIfTQ8CITHse4hYfq0JE5szaT8JAknuXhUaAgtZ1bn0SFLFlGG47ojQ0vZQg6k+\n\tx+60kSqjqc1EwoW4kaPrwOU/84ntYDAZHEG7T8U8WDGcly2IigbUuzCZ9Dvbnyo7BOXr\n\tbLhw==","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=S07dqOrAPYr6OhIdWBbRcmQQlcCzUS9aY7GNFfNZiek=;\n\tb=YjxJb+lgXJhGE7y2c2m0bDlCb/qeysaUaneSTcaMk+P2TDVAMeaa0/ZiWNVYeL/Mt2\n\tEJeOGV3ElPHIOkplopZoBAWmZBGRJacsEKxeXX4cpBceQzjAvHiOllrWDWjqS+/ps06M\n\t82X9kX3AF2agqp4fdHlhy+x+sjqGDAx57Cqlx1bGMKhF9jq9CvR7N2yeDk1i/iCddaee\n\teNaE7brJpQ1ZikHzVObFca6/vLgIrrrvdYdmRB97YrglVsIWiT5zRENjEKspAZFFt0N4\n\tosPj+xOkF0juGeTDMkrZSVlYn7aBIP1YQFBeqyxuivoCxsVrHRTvDUFUMj2v482QLr5s\n\tQNaQ==","X-Gm-Message-State":"AOAM532JKbDrfxgSJFruD1T0sn9PCeOb9xnfia6k/oBKVsq2PR5fqXlR\n\trjlxImHOkLzjz2Yh0QriMWMpmw==","X-Google-Smtp-Source":"ABdhPJyNC73LZ9iqA7ktRIzPwjoQ2XKt1K7ZWGAmsdviopq5Ih8O86yEjdsXlbPvGvNBsIg61oKOAA==","X-Received":"by 2002:a05:6512:31d5:: with SMTP id\n\tj21mr6907291lfe.83.1595086920281; \n\tSat, 18 Jul 2020 08:42:00 -0700 (PDT)","Date":"Sat, 18 Jul 2020 17:41:59 +0200","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Naushir Patuck <naush@raspberrypi.com>","Message-ID":"<20200718154159.GA571076@oden.dyn.berto.se>","References":"<20200717085410.732308-1-naush@raspberrypi.com>\n\t<20200717085410.732308-9-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20200717085410.732308-9-naush@raspberrypi.com>","Subject":"Re: [libcamera-devel] [PATCH v3 08/10] libcamera: pipeline:\n\traspberrypi: Add more robust stream buffer logic","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":"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>"}}]