[{"id":2255,"web_url":"https://patchwork.libcamera.org/comment/2255/","msgid":"<20190714103306.GC31102@wyvern>","date":"2019-07-14T10:33:06","subject":"Re: [libcamera-devel] [PATCH v2 05/16] libcamera: v4l2_videodevice:\n\tAdd helper to queue all buffers","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nThanks for your work.\n\nOn 2019-07-13 20:23:40 +0300, Laurent Pinchart wrote:\n> When starting the stream on a capture video device it is often needed to\n> queue all the allocated buffers. Add a helper method to do so, and\n> refactor the existing queueBuffer() method to make it clearer.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>  src/libcamera/include/v4l2_videodevice.h |  1 +\n>  src/libcamera/pipeline/ipu3/ipu3.cpp     | 13 ++---\n>  src/libcamera/v4l2_videodevice.cpp       | 63 +++++++++++++++++++++---\n>  test/v4l2_videodevice/buffer_sharing.cpp |  8 ++-\n>  test/v4l2_videodevice/capture_async.cpp  |  8 ++-\n>  5 files changed, 69 insertions(+), 24 deletions(-)\n> \n> diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\n> index b92df882568f..f948a41fb8c1 100644\n> --- a/src/libcamera/include/v4l2_videodevice.h\n> +++ b/src/libcamera/include/v4l2_videodevice.h\n> @@ -139,6 +139,7 @@ public:\n>  \tint releaseBuffers();\n>  \n>  \tint queueBuffer(Buffer *buffer);\n> +\tint queueAllBuffers(std::vector<std::unique_ptr<Buffer>> *buffers);\n\nCould this function return the vector instead of taking it as an \nargument? I think that would make sens as the queueAllBuffers() is an \n\"output\" while queueBuffer() is an \"input\".\n\n>  \tSignal<Buffer *> bufferReady;\n>  \n>  \tint streamOn();\n> diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> index 1abd20e5fee5..50457891e288 100644\n> --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> @@ -131,6 +131,7 @@ public:\n>  \tCameraSensor *sensor_;\n>  \n>  \tBufferPool pool_;\n> +\tstd::vector<std::unique_ptr<Buffer>> buffers_;\n>  };\n>  \n>  class IPU3Stream : public Stream\n> @@ -1430,11 +1431,9 @@ int CIO2Device::start()\n>  {\n>  \tint ret;\n>  \n> -\tfor (Buffer &buffer : pool_.buffers()) {\n> -\t\tret = output_->queueBuffer(&buffer);\n> -\t\tif (ret)\n> -\t\t\treturn ret;\n> -\t}\n> +\tret = output_->queueAllBuffers(&buffers_);\n> +\tif (ret)\n> +\t\treturn ret;\n>  \n>  \tret = output_->streamOn();\n>  \tif (ret)\n> @@ -1445,7 +1444,9 @@ int CIO2Device::start()\n>  \n>  int CIO2Device::stop()\n>  {\n> -\treturn output_->streamOff();\n> +\tint ret = output_->streamOff();\n> +\tbuffers_.clear();\n> +\treturn ret;\n>  }\n>  \n>  int CIO2Device::mediaBusToFormat(unsigned int code)\n> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> index 2d1e87a76c6f..af5ba803de45 100644\n> --- a/src/libcamera/v4l2_videodevice.cpp\n> +++ b/src/libcamera/v4l2_videodevice.cpp\n> @@ -894,8 +894,8 @@ int V4L2VideoDevice::releaseBuffers()\n>   */\n>  int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n>  {\n> +\tstruct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {};\n>  \tstruct v4l2_buffer buf = {};\n> -\tstruct v4l2_plane planes[VIDEO_MAX_PLANES] = {};\n>  \tint ret;\n>  \n>  \tbuf.index = buffer->index();\n> @@ -904,21 +904,20 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n>  \tbuf.field = V4L2_FIELD_NONE;\n>  \n>  \tbool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);\n> +\tconst std::vector<Plane> &planes = buffer->planes();\n>  \n>  \tif (buf.memory == V4L2_MEMORY_DMABUF) {\n>  \t\tif (multiPlanar) {\n> -\t\t\tfor (unsigned int p = 0;\n> -\t\t\t     p < buffer->planes().size();\n> -\t\t\t     p++)\n> -\t\t\t\tplanes[p].m.fd = buffer->planes()[p].dmabuf();\n> +\t\t\tfor (unsigned int p = 0; p < planes.size(); ++p)\n> +\t\t\t\tv4l2Planes[p].m.fd = planes[p].dmabuf();\n>  \t\t} else {\n> -\t\t\tbuf.m.fd = buffer->planes()[0].dmabuf();\n> +\t\t\tbuf.m.fd = planes[0].dmabuf();\n>  \t\t}\n>  \t}\n>  \n>  \tif (multiPlanar) {\n> -\t\tbuf.length = buffer->planes().size();\n> -\t\tbuf.m.planes = planes;\n> +\t\tbuf.length = planes.size();\n> +\t\tbuf.m.planes = v4l2Planes;\n>  \t}\n\nHum, this seems like an unrelated change which could be in its own \ncommit ;-)\n\n>  \n>  \tif (V4L2_TYPE_IS_OUTPUT(bufferType_)) {\n> @@ -944,6 +943,54 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n>  \treturn 0;\n>  }\n>  \n> +/**\n> + * \\brief Queue all buffers into the video device\n> + * \\param[out] buffers A vector of queued Buffer instances\n> + *\n> + * When starting video capture users of the video device often need to queue\n> + * all allocated buffers to the device. This helper method simplifies the\n> + * implementation of the user by queuing all buffers and populating the\n> + * \\a buffers vector with Buffer instances for each queued buffer.\n> + *\n> + * This method is meant to be used with video capture devices internal to a\n> + * pipeline handler, such as ISP statistics capture devices, or raw CSI-2\n> + * receivers. For video capture devices facing applications, buffers shall\n> + * instead be queued when requests are received, and for video output devices,\n> + * buffers shall be queued when frames are ready to be output.\n> + *\n> + * The caller shall ensure that the \\a buffers vector remains valid until all\n> + * the queued buffers are dequeued, either during capture, or by stopping the\n> + * video device.\n> + *\n> + * Calling this method on an output device or on a device that has buffers\n> + * already queued is an error and will return -EINVAL.\n> + *\n> + * \\return 0 on success or a negative error code otherwise\n> + */\n> +int V4L2VideoDevice::queueAllBuffers(std::vector<std::unique_ptr<Buffer>> *buffers)\n> +{\n> +\tint ret;\n> +\n> +\tif (queuedBuffersCount_)\n> +\t\treturn -EINVAL;\n> +\n> +\tif (V4L2_TYPE_IS_OUTPUT(bufferType_))\n> +\t\treturn -EINVAL;\n> +\n> +\tbuffers->clear();\n> +\n> +\tfor (unsigned int i = 0; i < bufferPool_->count(); ++i) {\n> +\t\tBuffer *buffer = new Buffer();\n> +\t\tbuffer->index_ = i;\n> +\t\tbuffers->emplace_back(buffer);\n> +\t\tret = queueBuffer(buffer);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n>  /**\n>   * \\brief Dequeue the next available buffer from the video device\n>   *\n> diff --git a/test/v4l2_videodevice/buffer_sharing.cpp b/test/v4l2_videodevice/buffer_sharing.cpp\n> index cc724b226619..459bd238fe97 100644\n> --- a/test/v4l2_videodevice/buffer_sharing.cpp\n> +++ b/test/v4l2_videodevice/buffer_sharing.cpp\n> @@ -117,11 +117,9 @@ protected:\n>  \t\tcapture_->bufferReady.connect(this, &BufferSharingTest::captureBufferReady);\n>  \t\toutput_->bufferReady.connect(this, &BufferSharingTest::outputBufferReady);\n>  \n> -\t\t/* Queue all the buffers to the capture device. */\n> -\t\tfor (Buffer &buffer : pool_.buffers()) {\n> -\t\t\tif (capture_->queueBuffer(&buffer))\n> -\t\t\t\treturn TestFail;\n> -\t\t}\n> +\t\tstd::vector<std::unique_ptr<Buffer>> buffers;\n> +\t\tif (capture_->queueAllBuffers(&buffers))\n> +\t\t\treturn TestFail;\n>  \n>  \t\tret = capture_->streamOn();\n>  \t\tif (ret) {\n> diff --git a/test/v4l2_videodevice/capture_async.cpp b/test/v4l2_videodevice/capture_async.cpp\n> index cea4fffbf7a5..c6d6ec6b74bd 100644\n> --- a/test/v4l2_videodevice/capture_async.cpp\n> +++ b/test/v4l2_videodevice/capture_async.cpp\n> @@ -46,11 +46,9 @@ protected:\n>  \n>  \t\tcapture_->bufferReady.connect(this, &CaptureAsyncTest::receiveBuffer);\n>  \n> -\t\t/* Queue all the buffers to the device. */\n> -\t\tfor (Buffer &b : pool_.buffers()) {\n> -\t\t\tif (capture_->queueBuffer(&b))\n> -\t\t\t\treturn TestFail;\n> -\t\t}\n> +\t\tstd::vector<std::unique_ptr<Buffer>> buffers;\n> +\t\tif (capture_->queueAllBuffers(&buffers))\n> +\t\t\treturn TestFail;\n>  \n>  \t\tret = capture_->streamOn();\n>  \t\tif (ret)\n> -- \n> Regards,\n> \n> Laurent Pinchart\n> \n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-pl1-x642.google.com (mail-pl1-x642.google.com\n\t[IPv6:2607:f8b0:4864:20::642])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 957A861572\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Jul 2019 12:33:13 +0200 (CEST)","by mail-pl1-x642.google.com with SMTP id i2so6891107plt.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Jul 2019 03:33:13 -0700 (PDT)","from localhost (softbank126159224182.bbtec.net. [126.159.224.182])\n\tby smtp.gmail.com with ESMTPSA id\n\tw22sm14383487pfi.175.2019.07.14.03.33.10\n\t(version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256);\n\tSun, 14 Jul 2019 03:33:10 -0700 (PDT)"],"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\t:user-agent; bh=KZklpqVhQeh54WwRLnJSVYgvl51/BeWldWgU8Yv20Vc=;\n\tb=03Cbje3v8sxwRnSSn9zV+PAl8xSRWDNTXz81QytBDrbV0iPSTF0KQfvVNnYgbWK7Ya\n\tJQ/4Tu5rEieQ+VNQhcmvAKl1MlvxwJBAYwKHu7s5BW+3EJXoYVS/MSUvU9/nFCUMUSHk\n\tx2PF/uuS+vYaL8gF3+t4ABfbxpiT6u9noU6Vxut0pa/1pK+g6xj9JTnCH3+FGNtUtGG8\n\tbO18oEFWtszNCz3tsYIOl0wZsPDMaCRKJw7NSFjUzfa9i9+d0IJVluwwxD9Yz0OfQDTB\n\tGCNncLcqsKdueHgI3kiP5Y6WFxYw8kcKyspB5URg2YUpBSR59PWk3boj4ShOgRYEtXWh\n\tFAXA==","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:user-agent;\n\tbh=KZklpqVhQeh54WwRLnJSVYgvl51/BeWldWgU8Yv20Vc=;\n\tb=IaNUCiMxLCgv3Inwn0fmI91WOw/CpQWufYR1IGJzagx4jBYqhmy0Qa5LDBMcwgUlox\n\ti0BdKCKPFbXV7JMf6XV98V5hRVXnfgJsoNc/kFiBu8S9wr0pGvIKxgQ7QOgXZvlDFKM5\n\tI7d+0aj5PS4xtG7hov3B9e4ap5nUUqXnUrAcyRGMHA6UetFpcsj3DWQzjorncS0CAR9y\n\t5AGNEHCBiDSf2Xj5rnknrk+oT1F+ajpRfBdPfkK9mGzSS/XGH10y77gUQBwMfHzIk0Jb\n\t35jkkfqMRuUhFf7saaSrCwJYh2EGvbL40bAM9+ungzptuMtcDpD0tjOWgqNrgbrs05nF\n\t6hjw==","X-Gm-Message-State":"APjAAAVBE6WLlODJOm9b/NmcvTJ/WV/HJQmplzBblz2UjurMdGJ2WInB\n\tY9mobVWEFBris+QGn9c4/3s=","X-Google-Smtp-Source":"APXvYqxJz9Xw0BxEoIfO3Ybi84VuncK+MSV1xttxeqwIN8emcVVuItX7ua5MtIrdVUnlLy35iYejvg==","X-Received":"by 2002:a17:902:2b8a:: with SMTP id\n\tl10mr22059012plb.283.1563100391714; \n\tSun, 14 Jul 2019 03:33:11 -0700 (PDT)","Date":"Sun, 14 Jul 2019 19:33:06 +0900","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190714103306.GC31102@wyvern>","References":"<20190713172351.25452-1-laurent.pinchart@ideasonboard.com>\n\t<20190713172351.25452-6-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190713172351.25452-6-laurent.pinchart@ideasonboard.com>","User-Agent":"Mutt/1.12.1 (2019-06-15)","Subject":"Re: [libcamera-devel] [PATCH v2 05/16] libcamera: v4l2_videodevice:\n\tAdd helper to queue all buffers","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":"Sun, 14 Jul 2019 10:33:14 -0000"}},{"id":2259,"web_url":"https://patchwork.libcamera.org/comment/2259/","msgid":"<20190714104307.GF6043@pendragon.ideasonboard.com>","date":"2019-07-14T10:43:07","subject":"Re: [libcamera-devel] [PATCH v2 05/16] libcamera: v4l2_videodevice:\n\tAdd helper to queue all buffers","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nOn Sun, Jul 14, 2019 at 07:33:06PM +0900, Niklas Söderlund wrote:\n> On 2019-07-13 20:23:40 +0300, Laurent Pinchart wrote:\n> > When starting the stream on a capture video device it is often needed to\n> > queue all the allocated buffers. Add a helper method to do so, and\n> > refactor the existing queueBuffer() method to make it clearer.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >  src/libcamera/include/v4l2_videodevice.h |  1 +\n> >  src/libcamera/pipeline/ipu3/ipu3.cpp     | 13 ++---\n> >  src/libcamera/v4l2_videodevice.cpp       | 63 +++++++++++++++++++++---\n> >  test/v4l2_videodevice/buffer_sharing.cpp |  8 ++-\n> >  test/v4l2_videodevice/capture_async.cpp  |  8 ++-\n> >  5 files changed, 69 insertions(+), 24 deletions(-)\n> > \n> > diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\n> > index b92df882568f..f948a41fb8c1 100644\n> > --- a/src/libcamera/include/v4l2_videodevice.h\n> > +++ b/src/libcamera/include/v4l2_videodevice.h\n> > @@ -139,6 +139,7 @@ public:\n> >  \tint releaseBuffers();\n> >  \n> >  \tint queueBuffer(Buffer *buffer);\n> > +\tint queueAllBuffers(std::vector<std::unique_ptr<Buffer>> *buffers);\n> \n> Could this function return the vector instead of taking it as an \n> argument? I think that would make sens as the queueAllBuffers() is an \n> \"output\" while queueBuffer() is an \"input\".\n\nI'll do that.\n\n> >  \tSignal<Buffer *> bufferReady;\n> >  \n> >  \tint streamOn();\n> > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > index 1abd20e5fee5..50457891e288 100644\n> > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > @@ -131,6 +131,7 @@ public:\n> >  \tCameraSensor *sensor_;\n> >  \n> >  \tBufferPool pool_;\n> > +\tstd::vector<std::unique_ptr<Buffer>> buffers_;\n> >  };\n> >  \n> >  class IPU3Stream : public Stream\n> > @@ -1430,11 +1431,9 @@ int CIO2Device::start()\n> >  {\n> >  \tint ret;\n> >  \n> > -\tfor (Buffer &buffer : pool_.buffers()) {\n> > -\t\tret = output_->queueBuffer(&buffer);\n> > -\t\tif (ret)\n> > -\t\t\treturn ret;\n> > -\t}\n> > +\tret = output_->queueAllBuffers(&buffers_);\n> > +\tif (ret)\n> > +\t\treturn ret;\n> >  \n> >  \tret = output_->streamOn();\n> >  \tif (ret)\n> > @@ -1445,7 +1444,9 @@ int CIO2Device::start()\n> >  \n> >  int CIO2Device::stop()\n> >  {\n> > -\treturn output_->streamOff();\n> > +\tint ret = output_->streamOff();\n> > +\tbuffers_.clear();\n> > +\treturn ret;\n> >  }\n> >  \n> >  int CIO2Device::mediaBusToFormat(unsigned int code)\n> > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> > index 2d1e87a76c6f..af5ba803de45 100644\n> > --- a/src/libcamera/v4l2_videodevice.cpp\n> > +++ b/src/libcamera/v4l2_videodevice.cpp\n> > @@ -894,8 +894,8 @@ int V4L2VideoDevice::releaseBuffers()\n> >   */\n> >  int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n> >  {\n> > +\tstruct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {};\n> >  \tstruct v4l2_buffer buf = {};\n> > -\tstruct v4l2_plane planes[VIDEO_MAX_PLANES] = {};\n> >  \tint ret;\n> >  \n> >  \tbuf.index = buffer->index();\n> > @@ -904,21 +904,20 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n> >  \tbuf.field = V4L2_FIELD_NONE;\n> >  \n> >  \tbool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);\n> > +\tconst std::vector<Plane> &planes = buffer->planes();\n> >  \n> >  \tif (buf.memory == V4L2_MEMORY_DMABUF) {\n> >  \t\tif (multiPlanar) {\n> > -\t\t\tfor (unsigned int p = 0;\n> > -\t\t\t     p < buffer->planes().size();\n> > -\t\t\t     p++)\n> > -\t\t\t\tplanes[p].m.fd = buffer->planes()[p].dmabuf();\n> > +\t\t\tfor (unsigned int p = 0; p < planes.size(); ++p)\n> > +\t\t\t\tv4l2Planes[p].m.fd = planes[p].dmabuf();\n> >  \t\t} else {\n> > -\t\t\tbuf.m.fd = buffer->planes()[0].dmabuf();\n> > +\t\t\tbuf.m.fd = planes[0].dmabuf();\n> >  \t\t}\n> >  \t}\n> >  \n> >  \tif (multiPlanar) {\n> > -\t\tbuf.length = buffer->planes().size();\n> > -\t\tbuf.m.planes = planes;\n> > +\t\tbuf.length = planes.size();\n> > +\t\tbuf.m.planes = v4l2Planes;\n> >  \t}\n> \n> Hum, this seems like an unrelated change which could be in its own \n> commit ;-)\n\nDidn't the commit message mention refactoring queueBuffer() ? :-)\n\n> >  \n> >  \tif (V4L2_TYPE_IS_OUTPUT(bufferType_)) {\n> > @@ -944,6 +943,54 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n> >  \treturn 0;\n> >  }\n> >  \n> > +/**\n> > + * \\brief Queue all buffers into the video device\n> > + * \\param[out] buffers A vector of queued Buffer instances\n> > + *\n> > + * When starting video capture users of the video device often need to queue\n> > + * all allocated buffers to the device. This helper method simplifies the\n> > + * implementation of the user by queuing all buffers and populating the\n> > + * \\a buffers vector with Buffer instances for each queued buffer.\n> > + *\n> > + * This method is meant to be used with video capture devices internal to a\n> > + * pipeline handler, such as ISP statistics capture devices, or raw CSI-2\n> > + * receivers. For video capture devices facing applications, buffers shall\n> > + * instead be queued when requests are received, and for video output devices,\n> > + * buffers shall be queued when frames are ready to be output.\n> > + *\n> > + * The caller shall ensure that the \\a buffers vector remains valid until all\n> > + * the queued buffers are dequeued, either during capture, or by stopping the\n> > + * video device.\n> > + *\n> > + * Calling this method on an output device or on a device that has buffers\n> > + * already queued is an error and will return -EINVAL.\n> > + *\n> > + * \\return 0 on success or a negative error code otherwise\n> > + */\n> > +int V4L2VideoDevice::queueAllBuffers(std::vector<std::unique_ptr<Buffer>> *buffers)\n> > +{\n> > +\tint ret;\n> > +\n> > +\tif (queuedBuffersCount_)\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tif (V4L2_TYPE_IS_OUTPUT(bufferType_))\n> > +\t\treturn -EINVAL;\n> > +\n> > +\tbuffers->clear();\n> > +\n> > +\tfor (unsigned int i = 0; i < bufferPool_->count(); ++i) {\n> > +\t\tBuffer *buffer = new Buffer();\n> > +\t\tbuffer->index_ = i;\n> > +\t\tbuffers->emplace_back(buffer);\n> > +\t\tret = queueBuffer(buffer);\n> > +\t\tif (ret)\n> > +\t\t\treturn ret;\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> >  /**\n> >   * \\brief Dequeue the next available buffer from the video device\n> >   *\n> > diff --git a/test/v4l2_videodevice/buffer_sharing.cpp b/test/v4l2_videodevice/buffer_sharing.cpp\n> > index cc724b226619..459bd238fe97 100644\n> > --- a/test/v4l2_videodevice/buffer_sharing.cpp\n> > +++ b/test/v4l2_videodevice/buffer_sharing.cpp\n> > @@ -117,11 +117,9 @@ protected:\n> >  \t\tcapture_->bufferReady.connect(this, &BufferSharingTest::captureBufferReady);\n> >  \t\toutput_->bufferReady.connect(this, &BufferSharingTest::outputBufferReady);\n> >  \n> > -\t\t/* Queue all the buffers to the capture device. */\n> > -\t\tfor (Buffer &buffer : pool_.buffers()) {\n> > -\t\t\tif (capture_->queueBuffer(&buffer))\n> > -\t\t\t\treturn TestFail;\n> > -\t\t}\n> > +\t\tstd::vector<std::unique_ptr<Buffer>> buffers;\n> > +\t\tif (capture_->queueAllBuffers(&buffers))\n> > +\t\t\treturn TestFail;\n> >  \n> >  \t\tret = capture_->streamOn();\n> >  \t\tif (ret) {\n> > diff --git a/test/v4l2_videodevice/capture_async.cpp b/test/v4l2_videodevice/capture_async.cpp\n> > index cea4fffbf7a5..c6d6ec6b74bd 100644\n> > --- a/test/v4l2_videodevice/capture_async.cpp\n> > +++ b/test/v4l2_videodevice/capture_async.cpp\n> > @@ -46,11 +46,9 @@ protected:\n> >  \n> >  \t\tcapture_->bufferReady.connect(this, &CaptureAsyncTest::receiveBuffer);\n> >  \n> > -\t\t/* Queue all the buffers to the device. */\n> > -\t\tfor (Buffer &b : pool_.buffers()) {\n> > -\t\t\tif (capture_->queueBuffer(&b))\n> > -\t\t\t\treturn TestFail;\n> > -\t\t}\n> > +\t\tstd::vector<std::unique_ptr<Buffer>> buffers;\n> > +\t\tif (capture_->queueAllBuffers(&buffers))\n> > +\t\t\treturn TestFail;\n> >  \n> >  \t\tret = capture_->streamOn();\n> >  \t\tif (ret)\n> > -- \n> > Regards,\n> > \n> > Laurent Pinchart\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":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8F1D661572\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Jul 2019 12:43:36 +0200 (CEST)","from pendragon.ideasonboard.com (softbank126159224182.bbtec.net\n\t[126.159.224.182])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 3C1A62B2;\n\tSun, 14 Jul 2019 12:43:34 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1563101016;\n\tbh=vlVlhWSiwrWF6mIAgky2j6PpTcN6lSkeSPLVZVBqSdY=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=V2/DuUf0F4Rap6CikOVpkxYzx0Oq8eM/JWXHsdMHqPml10yKalqOAZjF95KTX9Yn1\n\t3NBGQqAMDlYGgBoMvsCAbp0K0AVCo2KNaPrZBCxkei19OAWPN+KFXi669UISid3uV6\n\tIZJWS/noM4eOs1Nlodie1b43hyAzbJDkVHHEamJs=","Date":"Sun, 14 Jul 2019 13:43:07 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190714104307.GF6043@pendragon.ideasonboard.com>","References":"<20190713172351.25452-1-laurent.pinchart@ideasonboard.com>\n\t<20190713172351.25452-6-laurent.pinchart@ideasonboard.com>\n\t<20190714103306.GC31102@wyvern>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190714103306.GC31102@wyvern>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v2 05/16] libcamera: v4l2_videodevice:\n\tAdd helper to queue all buffers","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":"Sun, 14 Jul 2019 10:43:36 -0000"}},{"id":2261,"web_url":"https://patchwork.libcamera.org/comment/2261/","msgid":"<20190714104606.GF31102@wyvern>","date":"2019-07-14T10:46:06","subject":"Re: [libcamera-devel] [PATCH v2 05/16] libcamera: v4l2_videodevice:\n\tAdd helper to queue all buffers","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/people/5/","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"content":"Hi Laurent,\n\nOn 2019-07-14 13:43:07 +0300, Laurent Pinchart wrote:\n> Hi Niklas,\n> \n> On Sun, Jul 14, 2019 at 07:33:06PM +0900, Niklas Söderlund wrote:\n> > On 2019-07-13 20:23:40 +0300, Laurent Pinchart wrote:\n> > > When starting the stream on a capture video device it is often needed to\n> > > queue all the allocated buffers. Add a helper method to do so, and\n> > > refactor the existing queueBuffer() method to make it clearer.\n> > > \n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > ---\n> > >  src/libcamera/include/v4l2_videodevice.h |  1 +\n> > >  src/libcamera/pipeline/ipu3/ipu3.cpp     | 13 ++---\n> > >  src/libcamera/v4l2_videodevice.cpp       | 63 +++++++++++++++++++++---\n> > >  test/v4l2_videodevice/buffer_sharing.cpp |  8 ++-\n> > >  test/v4l2_videodevice/capture_async.cpp  |  8 ++-\n> > >  5 files changed, 69 insertions(+), 24 deletions(-)\n> > > \n> > > diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\n> > > index b92df882568f..f948a41fb8c1 100644\n> > > --- a/src/libcamera/include/v4l2_videodevice.h\n> > > +++ b/src/libcamera/include/v4l2_videodevice.h\n> > > @@ -139,6 +139,7 @@ public:\n> > >  \tint releaseBuffers();\n> > >  \n> > >  \tint queueBuffer(Buffer *buffer);\n> > > +\tint queueAllBuffers(std::vector<std::unique_ptr<Buffer>> *buffers);\n> > \n> > Could this function return the vector instead of taking it as an \n> > argument? I think that would make sens as the queueAllBuffers() is an \n> > \"output\" while queueBuffer() is an \"input\".\n> \n> I'll do that.\n> \n> > >  \tSignal<Buffer *> bufferReady;\n> > >  \n> > >  \tint streamOn();\n> > > diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > index 1abd20e5fee5..50457891e288 100644\n> > > --- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n> > > @@ -131,6 +131,7 @@ public:\n> > >  \tCameraSensor *sensor_;\n> > >  \n> > >  \tBufferPool pool_;\n> > > +\tstd::vector<std::unique_ptr<Buffer>> buffers_;\n> > >  };\n> > >  \n> > >  class IPU3Stream : public Stream\n> > > @@ -1430,11 +1431,9 @@ int CIO2Device::start()\n> > >  {\n> > >  \tint ret;\n> > >  \n> > > -\tfor (Buffer &buffer : pool_.buffers()) {\n> > > -\t\tret = output_->queueBuffer(&buffer);\n> > > -\t\tif (ret)\n> > > -\t\t\treturn ret;\n> > > -\t}\n> > > +\tret = output_->queueAllBuffers(&buffers_);\n> > > +\tif (ret)\n> > > +\t\treturn ret;\n> > >  \n> > >  \tret = output_->streamOn();\n> > >  \tif (ret)\n> > > @@ -1445,7 +1444,9 @@ int CIO2Device::start()\n> > >  \n> > >  int CIO2Device::stop()\n> > >  {\n> > > -\treturn output_->streamOff();\n> > > +\tint ret = output_->streamOff();\n> > > +\tbuffers_.clear();\n> > > +\treturn ret;\n> > >  }\n> > >  \n> > >  int CIO2Device::mediaBusToFormat(unsigned int code)\n> > > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> > > index 2d1e87a76c6f..af5ba803de45 100644\n> > > --- a/src/libcamera/v4l2_videodevice.cpp\n> > > +++ b/src/libcamera/v4l2_videodevice.cpp\n> > > @@ -894,8 +894,8 @@ int V4L2VideoDevice::releaseBuffers()\n> > >   */\n> > >  int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n> > >  {\n> > > +\tstruct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {};\n> > >  \tstruct v4l2_buffer buf = {};\n> > > -\tstruct v4l2_plane planes[VIDEO_MAX_PLANES] = {};\n> > >  \tint ret;\n> > >  \n> > >  \tbuf.index = buffer->index();\n> > > @@ -904,21 +904,20 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n> > >  \tbuf.field = V4L2_FIELD_NONE;\n> > >  \n> > >  \tbool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);\n> > > +\tconst std::vector<Plane> &planes = buffer->planes();\n> > >  \n> > >  \tif (buf.memory == V4L2_MEMORY_DMABUF) {\n> > >  \t\tif (multiPlanar) {\n> > > -\t\t\tfor (unsigned int p = 0;\n> > > -\t\t\t     p < buffer->planes().size();\n> > > -\t\t\t     p++)\n> > > -\t\t\t\tplanes[p].m.fd = buffer->planes()[p].dmabuf();\n> > > +\t\t\tfor (unsigned int p = 0; p < planes.size(); ++p)\n> > > +\t\t\t\tv4l2Planes[p].m.fd = planes[p].dmabuf();\n> > >  \t\t} else {\n> > > -\t\t\tbuf.m.fd = buffer->planes()[0].dmabuf();\n> > > +\t\t\tbuf.m.fd = planes[0].dmabuf();\n> > >  \t\t}\n> > >  \t}\n> > >  \n> > >  \tif (multiPlanar) {\n> > > -\t\tbuf.length = buffer->planes().size();\n> > > -\t\tbuf.m.planes = planes;\n> > > +\t\tbuf.length = planes.size();\n> > > +\t\tbuf.m.planes = v4l2Planes;\n> > >  \t}\n> > \n> > Hum, this seems like an unrelated change which could be in its own \n> > commit ;-)\n> \n> Didn't the commit message mention refactoring queueBuffer() ? :-)\n\nOhh my bad :-)\n\nWith the return type fixed for queueAllBuffers(),\n\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\n> \n> > >  \n> > >  \tif (V4L2_TYPE_IS_OUTPUT(bufferType_)) {\n> > > @@ -944,6 +943,54 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)\n> > >  \treturn 0;\n> > >  }\n> > >  \n> > > +/**\n> > > + * \\brief Queue all buffers into the video device\n> > > + * \\param[out] buffers A vector of queued Buffer instances\n> > > + *\n> > > + * When starting video capture users of the video device often need to queue\n> > > + * all allocated buffers to the device. This helper method simplifies the\n> > > + * implementation of the user by queuing all buffers and populating the\n> > > + * \\a buffers vector with Buffer instances for each queued buffer.\n> > > + *\n> > > + * This method is meant to be used with video capture devices internal to a\n> > > + * pipeline handler, such as ISP statistics capture devices, or raw CSI-2\n> > > + * receivers. For video capture devices facing applications, buffers shall\n> > > + * instead be queued when requests are received, and for video output devices,\n> > > + * buffers shall be queued when frames are ready to be output.\n> > > + *\n> > > + * The caller shall ensure that the \\a buffers vector remains valid until all\n> > > + * the queued buffers are dequeued, either during capture, or by stopping the\n> > > + * video device.\n> > > + *\n> > > + * Calling this method on an output device or on a device that has buffers\n> > > + * already queued is an error and will return -EINVAL.\n> > > + *\n> > > + * \\return 0 on success or a negative error code otherwise\n> > > + */\n> > > +int V4L2VideoDevice::queueAllBuffers(std::vector<std::unique_ptr<Buffer>> *buffers)\n> > > +{\n> > > +\tint ret;\n> > > +\n> > > +\tif (queuedBuffersCount_)\n> > > +\t\treturn -EINVAL;\n> > > +\n> > > +\tif (V4L2_TYPE_IS_OUTPUT(bufferType_))\n> > > +\t\treturn -EINVAL;\n> > > +\n> > > +\tbuffers->clear();\n> > > +\n> > > +\tfor (unsigned int i = 0; i < bufferPool_->count(); ++i) {\n> > > +\t\tBuffer *buffer = new Buffer();\n> > > +\t\tbuffer->index_ = i;\n> > > +\t\tbuffers->emplace_back(buffer);\n> > > +\t\tret = queueBuffer(buffer);\n> > > +\t\tif (ret)\n> > > +\t\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\treturn 0;\n> > > +}\n> > > +\n> > >  /**\n> > >   * \\brief Dequeue the next available buffer from the video device\n> > >   *\n> > > diff --git a/test/v4l2_videodevice/buffer_sharing.cpp b/test/v4l2_videodevice/buffer_sharing.cpp\n> > > index cc724b226619..459bd238fe97 100644\n> > > --- a/test/v4l2_videodevice/buffer_sharing.cpp\n> > > +++ b/test/v4l2_videodevice/buffer_sharing.cpp\n> > > @@ -117,11 +117,9 @@ protected:\n> > >  \t\tcapture_->bufferReady.connect(this, &BufferSharingTest::captureBufferReady);\n> > >  \t\toutput_->bufferReady.connect(this, &BufferSharingTest::outputBufferReady);\n> > >  \n> > > -\t\t/* Queue all the buffers to the capture device. */\n> > > -\t\tfor (Buffer &buffer : pool_.buffers()) {\n> > > -\t\t\tif (capture_->queueBuffer(&buffer))\n> > > -\t\t\t\treturn TestFail;\n> > > -\t\t}\n> > > +\t\tstd::vector<std::unique_ptr<Buffer>> buffers;\n> > > +\t\tif (capture_->queueAllBuffers(&buffers))\n> > > +\t\t\treturn TestFail;\n> > >  \n> > >  \t\tret = capture_->streamOn();\n> > >  \t\tif (ret) {\n> > > diff --git a/test/v4l2_videodevice/capture_async.cpp b/test/v4l2_videodevice/capture_async.cpp\n> > > index cea4fffbf7a5..c6d6ec6b74bd 100644\n> > > --- a/test/v4l2_videodevice/capture_async.cpp\n> > > +++ b/test/v4l2_videodevice/capture_async.cpp\n> > > @@ -46,11 +46,9 @@ protected:\n> > >  \n> > >  \t\tcapture_->bufferReady.connect(this, &CaptureAsyncTest::receiveBuffer);\n> > >  \n> > > -\t\t/* Queue all the buffers to the device. */\n> > > -\t\tfor (Buffer &b : pool_.buffers()) {\n> > > -\t\t\tif (capture_->queueBuffer(&b))\n> > > -\t\t\t\treturn TestFail;\n> > > -\t\t}\n> > > +\t\tstd::vector<std::unique_ptr<Buffer>> buffers;\n> > > +\t\tif (capture_->queueAllBuffers(&buffers))\n> > > +\t\t\treturn TestFail;\n> > >  \n> > >  \t\tret = capture_->streamOn();\n> > >  \t\tif (ret)\n> > > -- \n> > > Regards,\n> > > \n> > > Laurent Pinchart\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> -- \n> Regards,\n> \n> Laurent Pinchart","headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from mail-pg1-x541.google.com (mail-pg1-x541.google.com\n\t[IPv6:2607:f8b0:4864:20::541])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 00B3C61572\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Jul 2019 12:46:13 +0200 (CEST)","by mail-pg1-x541.google.com with SMTP id s1so91284pgr.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 14 Jul 2019 03:46:12 -0700 (PDT)","from localhost (softbank126159224182.bbtec.net. [126.159.224.182])\n\tby smtp.gmail.com with ESMTPSA id\n\tu16sm15318055pjb.2.2019.07.14.03.46.10\n\t(version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256);\n\tSun, 14 Jul 2019 03:46:11 -0700 (PDT)"],"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\t:user-agent; bh=GRisKTWZQ25uFojbb9/cEdFisGXKRgatdmbHb96fLSs=;\n\tb=1xlR1EVC+rvvLLPYCj6htgiABMxemPyQwV17sKQk8MloYPH01zSmHn+BBgP0sfyOKn\n\tVuh84YmFMvCcvH+2ZbvY0vit8HzLVa50x8tSvyH9OXQuOY/0hMR/s7JFVXBmNtenjI39\n\tatQErjVIoN1BIA0WwGqZH6UYV3juEEe27NkIm6W+CaqtNujDUKzcg38Dr4oSZlh2j8gi\n\tPz36gTJEm6kAjDUNvOgGSgDgjK9zwlAnEbpKRwteelJnK3P7ehemx+bPIf+ZQt3Ddk8H\n\tLvo6uGk06FzwJ/579p03uhY4EKesrJ5uIMd7t4su3PZNJ9lI9c7PePSInYnzcbplIkzY\n\tjQgw==","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:user-agent;\n\tbh=GRisKTWZQ25uFojbb9/cEdFisGXKRgatdmbHb96fLSs=;\n\tb=NfXTZeCI8eRQL0yRbmB3T6aKW2D0qvdk2UcIh5VPTQGXwV+tAae2/9VL81mIUZVwCh\n\trpHFwbmjtjvle8ual1E96EayDL+ux6iy1d7hoOxkqq5VZnmqavWr9vD19aAnlBViDKWN\n\t6IufEa4bYlJu5+NhwuwoVNp6QWICHUf2jdT3l6KH50m8lbYt4MQNEaOvXoF8nFLICYlS\n\tnEswjSb3EppkWV5OBAtGz+O+Bb9aRuZVTZhxSKqxJt3+ZhJWY7PxiUII4qIUA7uIjXIo\n\td01Wrjr8TYr/wJFn5XE1aiCe6TKRkClhez3x/NFHZCi2LAEGuYnxyK/yK5PU8ueHZAkt\n\tg+0A==","X-Gm-Message-State":"APjAAAU3iUCBBa1LMfPdKC7MnH+vC+9pV/M4IWla5zk7dP8lda1JR/3q\n\tx2DBNq2alfJEVSUSmE427bHQZBmPTvs=","X-Google-Smtp-Source":"APXvYqyMhhUfr+7ZgrBD/fsMo0awFuqdanzTha9ppwq9yTG0fA68aGB44NmSgtR/d6Jd8bH2AY7B/g==","X-Received":"by 2002:a17:90b:d82:: with SMTP id\n\tbg2mr23276413pjb.87.1563101171706; \n\tSun, 14 Jul 2019 03:46:11 -0700 (PDT)","Date":"Sun, 14 Jul 2019 19:46:06 +0900","From":"Niklas =?iso-8859-1?q?S=F6derlund?= <niklas.soderlund@ragnatech.se>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190714104606.GF31102@wyvern>","References":"<20190713172351.25452-1-laurent.pinchart@ideasonboard.com>\n\t<20190713172351.25452-6-laurent.pinchart@ideasonboard.com>\n\t<20190714103306.GC31102@wyvern>\n\t<20190714104307.GF6043@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=iso-8859-1","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190714104307.GF6043@pendragon.ideasonboard.com>","User-Agent":"Mutt/1.12.1 (2019-06-15)","Subject":"Re: [libcamera-devel] [PATCH v2 05/16] libcamera: v4l2_videodevice:\n\tAdd helper to queue all buffers","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":"Sun, 14 Jul 2019 10:46:13 -0000"}}]