[{"id":39567,"web_url":"https://patchwork.libcamera.org/comment/39567/","msgid":"<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>","date":"2026-07-03T12:37:51","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"Hi Barnabas\n\nThanks for working on all this, very excited to see progress on this topic!\n\nUnfortunately I'm about to disappear on holiday for 2 weeks, so this\nreply is going to turn into a long list of questions that I've not had\na huge amount of time to think about, so apologies in advance for\nthat.\n\nOn Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n<barnabas.pocze@ideasonboard.com> wrote:\n>\n> This is the first RFC changeset for splitting requests and buffers. It largely\n> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n> already reviewed.\n>\n> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n>\n> ---\n>\n> # introduction\n>\n> The basic idea is that requests no longer have buffers when they are submitted,\n> and the camera keeps track of a set of buffers for each stream, and buffers will\n> be attached to requests from this pool in an unspecified order\n>\n> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n> is used to set which streams a request wants frames from.\n\nI guess I'm vaguely expecting the buffer pool mechanism to be to a\nlarge extent separate from the camera system. So the camera system\nwill obviously be a client of it, but otherwise they're not really\nintertwined. Is that likely to be the case here? Or maybe it's not\npossible.\n\nI'm also vaguely feeling an application might want to control the\nlifetime of the pool and contents. For example, when the camera is\nstopped, maybe you want to leave your buffers in the pool so that you\ncan simply restart it? Wasn't sure if that kind of behaviour is\nenvisaged here.\n\n>\n> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n> buffer for the given stream. If this buffer is not acceptable, then\n> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n>\n> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n> the `PipelineHandler` base class fills each request with buffers before\n> calling `queueRequestDevice()`.\n\nOne thing I raised a while back was whether there are applications\nthat want to target specific buffers at particular requests. I'm\nthinking of Android here, though Android remains a giant mystery to\nme. But maybe another application might have a reason to do that?\n\nThe thought was to leave *optional* buffers in request. If it's there,\nyou use it and otherwise the camera system goes to the buffer pool to\nget one. It sort of feels to me like it should be doable, but is it\nuseful?\n\nI used to wonder whether an application might want to hold back a\nnumber of buffers so that it could do a burst capture, guaranteeing to\nhave a buffer for every request. But I'm not so convinced by that,\npresumably you can check if you have enough buffers in the pool.\n\nThough having optional buffers would certainly ease migration to the new scheme!\n\n>\n>\n> # discussion points\n>\n> ## adding buffers before `Camera::start()`\n>\n> Currently buffers can only be added in the \"Running\" state. They could\n> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n> and putting it into `stop()` would be a bit asymmetric.\n\nIndeed, I've always wanted to queue requests before starting the camera!\n\n>\n> ## empty pool notification\n>\n> Currently there is no mechanism for the application to know how many\n> buffers it should keep in the pool. I think a signal to notify the application\n> when it should add more buffers for a given stream could be added. But the\n> main idea was to expose some kind of minimum buffer count quantity.\n>\n> ## requirements towards application wrt. buffers\n>\n> With this prototype, an application is essentially required to always process *all*\n> buffers in *all* completed requests, otherwise it might lose buffers. (This\n> applies to cancelled requests as well.) Is that reasonable?\n\nI think it sounds OK to expect applications to manage buffers, at\nleast to an extent. As I remarked above, I think maybe applications\nwill want to manage buffers for their own convenience.\n\n>\n> ## returning unused buffers\n>\n> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n> where `request == nullptr`. This works, but may not be the best interface.\n>\n> ## returning rejected buffers\n>\n> Pipeline handlers can reject buffers. But how should that be signalled to the\n> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n> But this is not ideal because there isn't really a way to distinguish it from\n> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n> because `FrameError` requires some other fields to be valid.\n>\n> ## extending `completeBuffer()` with stream parameter\n>\n> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n\nIt does feel a bit strange to me that buffers should know about\nstreams, and so on. I think I was expecting buffers/pools to be\nlargely independent of such things. But I accept there might be a good\nreason.\n\n>\n> ## fence timeout\n>\n> Previously a hard-coded timeout was used for fences. This is now removed.\n> Should there be a hard-coded fixed timeout for fences?\n>\n>\n> # TODO\n>\n> # converting more pipeline handlers\n>\n> Only the uvcvideo pipeline handler is converted to use the buffer pool\n> directly as an experiment, but more should be converted to really see\n> if this public api is a good fit for pipeline handlers. Especially something\n> like `imx8-isi` since that has a bit different architecture from the others.\n>\n> # minimum buffer count\n>\n> The applications need to know how many buffers should be kept in the pool\n> for a given stream for continuous streaming. This should be a property or\n> similar.\n\nYes, I guess so. In practice we always allocate way more than the\nminimum, simply because that avoids frame drops.\n\n>\n> # `FrameBuffer::Private::request()`\n>\n> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n> should probably be removed to fully decouple the two.\n\nOne other slightly unusual use case I'd like to add into the mix is\none I remember hearing on a Kamaros call. There's a stream of frames\ncoming back from a camera, but then there's a second stream, made from\nthe same sensor images, but which is generated only occasionally (so\nruns at a lower framerate).\n\nDoes the buffer pool mechanism give us a way to handle this? When a\nrequest completes there could be 3 outcomes - 1. here's your buffer,\n2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\nactually a frame generated for this stream on this occasion.\n\nThe final thing I'd like to discuss is how this relates to control\nqueues. Of course, strictly speaking the two subjects are independent,\nbut nonetheless I have a couple of questions.\n\n* The buffer/request split will obviously break the existing API and\ncause a certain amount of work. If we're going to have control queues,\nare we going to break everything again later, or do it all at once?\nJust wondering...\n\n* If you took control lists out of requests you might find there's\nalmost nothing left in them. Wanted to check we're OK with that just\nin case we were to end up there!\n\nAnyway, apologies for the big dump of questions and then running away.\nLook forward to hearing more on the subject!\n\nThanks\nDavid\n\n>\n> ---\n>\n> Barnabás Pőcze (54):\n>   apps: cam: Simplify buffer reuse\n>   libcamera: request: Disassociate buffer when cancelling\n>   libcamera: pipeline: Replace open-coded request cancellation\n>   libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n>   libcamera: pipeline: virtual: Make copy of request's buffer map\n>   libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n>   libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n>   v4l2: v4l2_camera: Avoid a level of indirection\n>   v4l2: v4l2_camera: Remove repated index checks\n>   v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n>   v4l2: v4l2_camera: Use actually allocated buffer count\n>   v4l2: v4l2_camera: Use buffer cookie for indexing\n>   v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n>   v4l2: v4l2_camera: Always clear pending requests\n>   v4l2: v4l2_camera: Clear completed requests when stopping\n>   v4l2: v4l2_camera: Provide buffers one by one\n>   test: fence: Disable temporarily\n>   libcamera: request: Remove `ReuseBuffers`\n>   libcamera: framebuffer: request(): Move to private type\n>   libcamera: framebuffer: Store associated Stream\n>   libcamera: camera: Add `StreamData`\n>   libcamera: camera: Add buffer pool\n>   libcamera: request: addBuffer(): Remove impl\n>   libcamera: request: Remove fence support\n>   libcamera: request: Store count of pending buffers\n>   libcamera: request: doCancelRequest(): Remove\n>   libcamera: pipeline_handler: Move constructor options to a separate\n>     type\n>   libcamera: pipeline_handler: Acquire buffers if not using pool\n>   libcamera: request: enableStream(): Add\n>   libcamera: camera: acquireBuffer(): Add\n>   libcamera: camera: rejectBuffer(): Add\n>   libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n>     function\n>   libcamera: pipeline_handler: Use `std::deque`\n>   libcamera: pipeline_handler: completeRequest(): Return request count\n>   libcamera: pipeline: uvcvideo: Use buffer pool prototype\n>   libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n>   libcamera: camera: bufferCompleted: Pass `Stream` as well\n>   libcamera: camera: queueRequest(): Adjust buffer map empty error\n>     message\n>   libcamera: camera: queueBuffer(): Reject if it has buffers\n>   apps: cam: Use camera buffer pool\n>   app: lc-compliance: Use camera buffer pool\n>   apps: lc-compliance: Add buffer pool tests\n>   test: Use camera buffer pool\n>   apps: qcam: Use camera buffer pool\n>   v4l2: Use camera buffer pool\n>   py: Use camera buffer pool\n>   gstreamer: Use camera buffer pool\n>   libcamera: request: Remove `ReuseFlag`\n>   android: Update imported files\n>   android: camera_request: Add helper for buffer conversion\n>   android: camera_device: Move fence restoration into\n>     `prepareToReturn()`\n>   android: Use camera buffer pool\n>   libcamera: request: Remove `addBuffer()`\n>   test: fence: Enable\n>\n>  .../guides/application-developer.rst          |    9 -\n>  Documentation/guides/pipeline-handler.rst     |   10 +-\n>  .../libhardware/include/hardware/camera3.h    |  360 +-\n>  .../include/hardware/camera_common.h          |  304 +-\n>  .../libhardware/include/hardware/gralloc.h    |   99 +-\n>  .../android/metadata/camera_metadata_hidden.h |   11 +-\n>  .../android/metadata/system/camera_metadata.h |   41 +-\n>  .../metadata/system/camera_metadata_tags.h    |  633 +-\n>  .../metadata/system/camera_vendor_tags.h      |   10 +-\n>  .../android/system/core/include/android/log.h |  450 +-\n>  .../core/include/cutils/native_handle.h       |   62 +-\n>  .../system/core/include/system/camera.h       |    4 +-\n>  .../core/include/system/graphics-base-v1.2.h  |   36 +\n>  .../core/include/system/graphics-base.h       |    1 +\n>  .../system/core/include/system/graphics.h     |   10 +-\n>  include/libcamera/camera.h                    |    5 +-\n>  include/libcamera/framebuffer.h               |    1 -\n>  include/libcamera/internal/camera.h           |   46 +-\n>  include/libcamera/internal/framebuffer.h      |    6 +\n>  include/libcamera/internal/pipeline_handler.h |   31 +-\n>  include/libcamera/internal/request.h          |   24 +-\n>  include/libcamera/request.h                   |   10 +-\n>  src/android/camera3_hal.cpp                   |    3 +\n>  src/android/camera_capabilities.cpp           |    3 +\n>  src/android/camera_device.cpp                 |  287 +-\n>  src/android/camera_device.h                   |    4 +\n>  src/android/camera_hal_manager.cpp            |    2 +-\n>  src/android/camera_ops.cpp                    |   16 +-\n>  src/android/camera_request.cpp                |   53 +-\n>  src/android/camera_request.h                  |   11 +-\n>  src/android/metadata/camera_metadata.c        |  183 +-\n>  .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n>  src/apps/cam/camera_session.cpp               |   36 +-\n>  src/apps/cam/camera_session.h                 |    2 +-\n>  src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n>  src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n>  src/apps/qcam/main_window.cpp                 |   82 +-\n>  src/apps/qcam/main_window.h                   |    1 -\n>  src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n>  src/libcamera/camera.cpp                      |  164 +-\n>  src/libcamera/fence.cpp                       |   15 +-\n>  src/libcamera/framebuffer.cpp                 |   57 +-\n>  src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n>  src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n>  src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n>  src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n>  src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n>  src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n>  .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n>  .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n>  src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n>  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n>  src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n>  src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n>  src/libcamera/pipeline_handler.cpp            |  260 +-\n>  src/libcamera/request.cpp                     |  290 +-\n>  src/py/cam/cam.py                             |   20 +-\n>  src/py/examples/simple-cam.py                 |   13 +-\n>  src/py/examples/simple-capture.py             |   20 +-\n>  src/py/examples/simple-continuous-capture.py  |   32 +-\n>  src/py/libcamera/py_main.cpp                  |   65 +-\n>  src/v4l2/v4l2_camera.cpp                      |  150 +-\n>  src/v4l2/v4l2_camera.h                        |   25 +-\n>  src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n>  src/v4l2/v4l2_camera_proxy.h                  |    3 -\n>  test/camera/buffer_import.cpp                 |   22 +-\n>  test/camera/camera_reconfigure.cpp            |   22 +-\n>  test/camera/capture.cpp                       |   24 +-\n>  test/camera/statemachine.cpp                  |    4 +-\n>  test/fence.cpp                                |  214 +-\n>  70 files changed, 9182 insertions(+), 1283 deletions(-)\n>  create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n>\n> --\n> 2.54.0","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 9C123C3261\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  3 Jul 2026 12:38:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A10A065FC6;\n\tFri,  3 Jul 2026 14:38:04 +0200 (CEST)","from mail-ed1-x530.google.com (mail-ed1-x530.google.com\n\t[IPv6:2a00:1450:4864:20::530])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2FA2865FC1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Jul 2026 14:38:03 +0200 (CEST)","by mail-ed1-x530.google.com with SMTP id\n\t4fb4d7f45d1cf-698bf7a1a2dso861403a12.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 03 Jul 2026 05:38:03 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"DxAJGn4B\"; dkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1783082282; cv=none;\n\td=google.com; s=arc-20260327;\n\tb=ay5DPZ9guFyQ/AohQzaFGv+16WzE/ZSVjnQM7DIQGsJUHQYaaXFJfIrpXKo6IBhMvo\n\thSriMmhaCwj+w0uWFwIg5fU8dv2r/53Hn15m5h3ELRZTossO98wICLydqFZodPr+fCr2\n\t2W2ZoGh6QdtO69vf7y9ODCS8RqZblcpL9YMcAWNJTF0TwZT61U2vmITr6HxX9KIjzJAY\n\tnFnF1/Bpv4lhUBaTgvZV2utp05hhZQMd3c0cvDN61vd3pAyksGCqSG5PQ7miTnn0tfYq\n\tO1tm+y7vNmW4CgPGsXWvdstIfuLmpvb3Y/dHiG+hFVZzVT0sh/bE/mqARtNEeQzvlHtf\n\twA9g==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n\ts=arc-20260327; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:dkim-signature;\n\tbh=fWy2iV115idYDFFZWF+v2o7Z1OHoNB/kE+hgeVCU3FM=;\n\tfh=6eMZ9Peh5oKJMXVlU5do7GxLXGl0cSCd64pkjvWpyo4=;\n\tb=V6bgmIIMEvIdMDWhaI1JSHFIxjV/elcMTVUzrHzUqbZTgQh4gzIBC74TgtkG/T/gfM\n\tv3uWbVbSrW1GfN8U9t1M9ElwpxaY4sI6BbXS8kl0dxmoWs3IjF6caQJQfqQmGweTH5E9\n\t0b2nXc5WP9SYqadq2ttmnl/W1X4+COpk8sxtMEJ33SsxbyHa+K0bP8jl189/fh/36m+P\n\tUd6wmDIlFTIjXD4ysz9oDUyIew5Fj6vZKzZqQZSUahYplzDc3k4sRfjy32sbBizg8Vy9\n\tEOzHQ0IOqVK7+AHslkL3O5q4zYbB3g0d6w4AqI865kx3IPNDcuNy94+rWrxQjdNoLalr\n\t0YiQ==; darn=lists.libcamera.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1783082282; x=1783687082;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=fWy2iV115idYDFFZWF+v2o7Z1OHoNB/kE+hgeVCU3FM=;\n\tb=DxAJGn4Bm0B6TzTZwBiivkvyE1dCW1MXizEm7+Mfgzc1DXhkh5M/NXGEE+SlaEVXHR\n\tNfyDnw+NB2rkqkVQBIbmJOzuiJxAwG5D+fNXCfSYo+Wq8QSYWPh5/pGfjaTkpvrqUKpx\n\tmLIv13BCnwFaj2CG89vwvieAZlZM52XuL2V7S4ZYrOfjkBVoa1pyWxEhMoCwpDmytvj1\n\tostmsHbl7DAM1oeVtJwAiLJbAwB0J0R7Ik6keudcsCrbelHS2RQn5f3DQxNZdbkr2t3w\n\tsvkfSBOUjR20rgvEIGDEBb/JMB/JBwmySqnw5FB7hDs52bo8KOmObKwQ52WAPHhIsXgQ\n\tGb6w==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1783082282; x=1783687082;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n\t:to:cc:subject:date:message-id:reply-to;\n\tbh=fWy2iV115idYDFFZWF+v2o7Z1OHoNB/kE+hgeVCU3FM=;\n\tb=rtau59I0e7H2iqcuW/Dz4DH1Q5gF+A3IoBVrazB/eo3YwcNBYNd686oZRghGEQu0un\n\t/cqz6MotNa+I5KdM8NAZuPIH5r4gLJcT5IxfLa9i33LWsZLNd/eRvPLGYr6avLCHW0pz\n\tJ2uvGC/mu/Uizk2HJZpVlEbTYYTa39gOGUz2KxdeKT4xxtQFIo6vej/pRaehoi+w88aA\n\t0S+LMEusB3bSQfEagdyOP067WWspw689uZohGRlur5Mbmz0acy/eX41cPwIMtgjP1wn5\n\tWmfwJdmzdFHtRe728fnat1KPO2Uk3G7JFRjn9LQC2F7uCcEqcBn6qRS4Lkm/PNAjDlxm\n\t8L5A==","X-Gm-Message-State":"AOJu0Yxuon6UyFKsA1Uq+rwPl5HUcWJovnQrAg79bFYr0o/j0Mr+sN+q\n\tBt41CJxH0IowAL08IQfvTIp+UitmKTcAtP4J/ET0kjjPLNqC3CUtDil0FC444zQhjzme3Ev0u5L\n\tLO8NuYB17HqZBsdwyfi310TnmF13S+K11DZSSxOcuJ6jqLgiCHsSfrT8=","X-Gm-Gg":"AfdE7cmc8zvMNDFS9mtSClzEYAbGah7fTwkt92+1T8wSTXtRXIy7Y3QSAfri5FG3IRq\n\tYRy6Y7jHCx2Gz7wcCEKmDX+lntWmfIcEVy2dT7nske3JGrH3rcbTnfIAOduguMcLgsiLXAtSjIu\n\tacIr9G3zyDl8KrzAhk8/P5gzMyV2eVTIGqStRJC0rXHJD7ObfqMcxEZ5m+aUsEN7Uvc2AqdlbsN\n\tROI2y3LrQWEweMuJTdKq6M5dyD5RSOv+UNEaqjO8FDqLMuhzIqmWp/Nu9Zhqfa4B48ie2h+VScH\n\tfrXSjGRVuxVriaPWk4PNiJCzSEtFos5dkIx0k6a4ANXZbbcsfIANSZF4GKAmAPz1i5qxGswDwau\n\tTm3FdY84Vqp5Jcg==","X-Received":"by 2002:a05:6402:428a:b0:698:3fd4:47da with SMTP id\n\t4fb4d7f45d1cf-6989f349104mr4753986a12.26.1783082282453;\n\tFri, 03 Jul 2026 05:38:02 -0700 (PDT)","MIME-Version":"1.0","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>","In-Reply-To":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Fri, 3 Jul 2026 13:37:51 +0100","X-Gm-Features":"AVVi8CfQHC-xwk1vyzU0a3yJOgCVrn8gpzC_VcD3LXtcBPcCSvVjA8ho-xdYFK0","Message-ID":"<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39569,"web_url":"https://patchwork.libcamera.org/comment/39569/","msgid":"<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>","date":"2026-07-03T14:37:45","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\nI have tried to answer the questions, let me know if I'd missed anything.\n\n2026. 07. 03. 14:37 keltezéssel, David Plowman írta:\n> Hi Barnabas\n> \n> Thanks for working on all this, very excited to see progress on this topic!\n> \n> Unfortunately I'm about to disappear on holiday for 2 weeks, so this\n> reply is going to turn into a long list of questions that I've not had\n> a huge amount of time to think about, so apologies in advance for\n> that.\n> \n> On Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n> <barnabas.pocze@ideasonboard.com> wrote:\n>>\n>> This is the first RFC changeset for splitting requests and buffers. It largely\n>> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n>> already reviewed.\n>>\n>> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n>>\n>> ---\n>>\n>> # introduction\n>>\n>> The basic idea is that requests no longer have buffers when they are submitted,\n>> and the camera keeps track of a set of buffers for each stream, and buffers will\n>> be attached to requests from this pool in an unspecified order\n>>\n>> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n>> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n>> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n>> is used to set which streams a request wants frames from.\n> \n> I guess I'm vaguely expecting the buffer pool mechanism to be to a\n> large extent separate from the camera system. So the camera system\n> will obviously be a client of it, but otherwise they're not really\n> intertwined. Is that likely to be the case here? Or maybe it's not\n> possible.\n\nThe buffer pool mechanism is implemented in the \"Camera\" and related types.\nAnd not in e.g. a separate `BufferPool` type. This was deemed the simpler\napproach. But there are no technical obstacles as far as I can tell.\nOr do you mean something else?\n\n\n> \n> I'm also vaguely feeling an application might want to control the\n> lifetime of the pool and contents. For example, when the camera is\n> stopped, maybe you want to leave your buffers in the pool so that you\n> can simply restart it? Wasn't sure if that kind of behaviour is\n> envisaged here.\n\nI don't think that option was discussed, but could be implemented.\nNonetheless then `configure()` has to clear the pool in any case,\nwhich is technically a bit more complicated to do.\n\n\n> \n>>\n>> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n>> buffer for the given stream. If this buffer is not acceptable, then\n>> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n>> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n>>\n>> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n>> the `PipelineHandler` base class fills each request with buffers before\n>> calling `queueRequestDevice()`.\n> \n> One thing I raised a while back was whether there are applications\n> that want to target specific buffers at particular requests. I'm\n> thinking of Android here, though Android remains a giant mystery to\n> me. But maybe another application might have a reason to do that?\n\nAndroid has caused quite a bit of headache, so in the end a switch\nto their \"new\" buffer model was made: https://source.android.com/docs/core/camera/buffer-management-api\n\nThis uses a similar pool based approach where requests no longer contain any buffers.\n\n\n> \n> The thought was to leave *optional* buffers in request. If it's there,\n> you use it and otherwise the camera system goes to the buffer pool to\n> get one. It sort of feels to me like it should be doable, but is it\n> useful?\n> \n> I used to wonder whether an application might want to hold back a\n> number of buffers so that it could do a burst capture, guaranteeing to\n> have a buffer for every request. But I'm not so convinced by that,\n> presumably you can check if you have enough buffers in the pool.\n> \n> Though having optional buffers would certainly ease migration to the new scheme!\n\nI don't have a satisfactory answer unfortunately. I think it's a matter\nof making a decision, it seems technically feasible. Of course it would\ncomplicate the core and pipeline handler parts.\n\nThere is also a question of how to handle requests that mix both:\nhaving some buffers and also some \"just\" enabled streams. Then\nfences must also not be forgotten about. And then it has to be evaluated\nhow many technical difficulties supporting this mixed model would cause for\nthe existing pipeline handler implementations.\n\nAn earlier prototype explored the idea of automatically adding buffers\nfrom requests to the pool when they are queued. This of course would\nbreak the association between buffers and requests, so it wouldn't\naddress your point. And it was decided not to go forward with this\ncompatibility behaviour in any case.\n\n\n> \n>>\n>>\n>> # discussion points\n>>\n>> ## adding buffers before `Camera::start()`\n>>\n>> Currently buffers can only be added in the \"Running\" state. They could\n>> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n>> and putting it into `stop()` would be a bit asymmetric.\n> \n> Indeed, I've always wanted to queue requests before starting the camera!\n> \n>>\n>> ## empty pool notification\n>>\n>> Currently there is no mechanism for the application to know how many\n>> buffers it should keep in the pool. I think a signal to notify the application\n>> when it should add more buffers for a given stream could be added. But the\n>> main idea was to expose some kind of minimum buffer count quantity.\n>>\n>> ## requirements towards application wrt. buffers\n>>\n>> With this prototype, an application is essentially required to always process *all*\n>> buffers in *all* completed requests, otherwise it might lose buffers. (This\n>> applies to cancelled requests as well.) Is that reasonable?\n> \n> I think it sounds OK to expect applications to manage buffers, at\n> least to an extent. As I remarked above, I think maybe applications\n> will want to manage buffers for their own convenience.\n> \n>>\n>> ## returning unused buffers\n>>\n>> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n>> where `request == nullptr`. This works, but may not be the best interface.\n>>\n>> ## returning rejected buffers\n>>\n>> Pipeline handlers can reject buffers. But how should that be signalled to the\n>> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n>> But this is not ideal because there isn't really a way to distinguish it from\n>> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n>> because `FrameError` requires some other fields to be valid.\n>>\n>> ## extending `completeBuffer()` with stream parameter\n>>\n>> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n>> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n>> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n>> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n> \n> It does feel a bit strange to me that buffers should know about\n> streams, and so on. I think I was expecting buffers/pools to be\n> largely independent of such things. But I accept there might be a good\n> reason.\n\nIndeed they shouldn't. But migrating straight to `completeBuffer(req, stream, buf)`\nworld where buffers have no idea about requests and streams\nis not as simple as I would have liked. Especially since most\npipeline handlers are written with the current model in mind\nwhere a buffer is already in a request associated with a stream.\nAnd so the actual stream is not even easily available at buffer\ncompletion time in many cases. So this is a compromise.\n\n\n> \n>>\n>> ## fence timeout\n>>\n>> Previously a hard-coded timeout was used for fences. This is now removed.\n>> Should there be a hard-coded fixed timeout for fences?\n>>\n>>\n>> # TODO\n>>\n>> # converting more pipeline handlers\n>>\n>> Only the uvcvideo pipeline handler is converted to use the buffer pool\n>> directly as an experiment, but more should be converted to really see\n>> if this public api is a good fit for pipeline handlers. Especially something\n>> like `imx8-isi` since that has a bit different architecture from the others.\n>>\n>> # minimum buffer count\n>>\n>> The applications need to know how many buffers should be kept in the pool\n>> for a given stream for continuous streaming. This should be a property or\n>> similar.\n> \n> Yes, I guess so. In practice we always allocate way more than the\n> minimum, simply because that avoids frame drops.\n\nYes, but this information can be useful if the buffer goes into a processing pipeline\nthat holds on to it, or if the applications creates its own `FrameBuffer`s without\nthe `FrameBufferAllocator`.\n\n\n> \n>>\n>> # `FrameBuffer::Private::request()`\n>>\n>> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n>> should probably be removed to fully decouple the two.\n> \n> One other slightly unusual use case I'd like to add into the mix is\n> one I remember hearing on a Kamaros call. There's a stream of frames\n> coming back from a camera, but then there's a second stream, made from\n> the same sensor images, but which is generated only occasionally (so\n> runs at a lower framerate).\n> \n> Does the buffer pool mechanism give us a way to handle this? When a\n> request completes there could be 3 outcomes - 1. here's your buffer,\n> 2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\n> actually a frame generated for this stream on this occasion.\n\nYou mean like a stream that might not supply a frame even if the\nrequest enables it, there are available buffers, and no errors\nare encountered? Or put differently, a stream that \"itself\" decides\nwhen to supply frames regardless of the streams in the request?\n\nIn that case currently (2) and (3) cannot be differentiated. But\nit's a matter of extending the buffer map in the request.\n\n\n> \n> The final thing I'd like to discuss is how this relates to control\n> queues. Of course, strictly speaking the two subjects are independent,\n> but nonetheless I have a couple of questions.\n> \n> * The buffer/request split will obviously break the existing API and\n> cause a certain amount of work. If we're going to have control queues,\n> are we going to break everything again later, or do it all at once?\n> Just wondering...\n\nI suppose it would be better to break the world once, but I'm no\nauthority on the question of libcamera stability and releases.\n\n\n> \n> * If you took control lists out of requests you might find there's\n> almost nothing left in them. Wanted to check we're OK with that just\n> in case we were to end up there!\n\nI think it's fine. A request would still have a \"cookie\" and the set\nof enabled streams. And it has a sequence number, status, a set of\nbuffers, and a set of metadata items when it completes.\n\nNonetheless we could explore getting rid of the application facing\n`Request` type and using something different, maybe something more\ncentered around using the numeric sequence number as the identity.\n\n\n> \n> Anyway, apologies for the big dump of questions and then running away.\n> Look forward to hearing more on the subject!\n> \n> Thanks\n> David\n> \n>>\n>> ---\n>>\n>> Barnabás Pőcze (54):\n>>    apps: cam: Simplify buffer reuse\n>>    libcamera: request: Disassociate buffer when cancelling\n>>    libcamera: pipeline: Replace open-coded request cancellation\n>>    libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n>>    libcamera: pipeline: virtual: Make copy of request's buffer map\n>>    libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n>>    libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n>>    v4l2: v4l2_camera: Avoid a level of indirection\n>>    v4l2: v4l2_camera: Remove repated index checks\n>>    v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n>>    v4l2: v4l2_camera: Use actually allocated buffer count\n>>    v4l2: v4l2_camera: Use buffer cookie for indexing\n>>    v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n>>    v4l2: v4l2_camera: Always clear pending requests\n>>    v4l2: v4l2_camera: Clear completed requests when stopping\n>>    v4l2: v4l2_camera: Provide buffers one by one\n>>    test: fence: Disable temporarily\n>>    libcamera: request: Remove `ReuseBuffers`\n>>    libcamera: framebuffer: request(): Move to private type\n>>    libcamera: framebuffer: Store associated Stream\n>>    libcamera: camera: Add `StreamData`\n>>    libcamera: camera: Add buffer pool\n>>    libcamera: request: addBuffer(): Remove impl\n>>    libcamera: request: Remove fence support\n>>    libcamera: request: Store count of pending buffers\n>>    libcamera: request: doCancelRequest(): Remove\n>>    libcamera: pipeline_handler: Move constructor options to a separate\n>>      type\n>>    libcamera: pipeline_handler: Acquire buffers if not using pool\n>>    libcamera: request: enableStream(): Add\n>>    libcamera: camera: acquireBuffer(): Add\n>>    libcamera: camera: rejectBuffer(): Add\n>>    libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n>>      function\n>>    libcamera: pipeline_handler: Use `std::deque`\n>>    libcamera: pipeline_handler: completeRequest(): Return request count\n>>    libcamera: pipeline: uvcvideo: Use buffer pool prototype\n>>    libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n>>    libcamera: camera: bufferCompleted: Pass `Stream` as well\n>>    libcamera: camera: queueRequest(): Adjust buffer map empty error\n>>      message\n>>    libcamera: camera: queueBuffer(): Reject if it has buffers\n>>    apps: cam: Use camera buffer pool\n>>    app: lc-compliance: Use camera buffer pool\n>>    apps: lc-compliance: Add buffer pool tests\n>>    test: Use camera buffer pool\n>>    apps: qcam: Use camera buffer pool\n>>    v4l2: Use camera buffer pool\n>>    py: Use camera buffer pool\n>>    gstreamer: Use camera buffer pool\n>>    libcamera: request: Remove `ReuseFlag`\n>>    android: Update imported files\n>>    android: camera_request: Add helper for buffer conversion\n>>    android: camera_device: Move fence restoration into\n>>      `prepareToReturn()`\n>>    android: Use camera buffer pool\n>>    libcamera: request: Remove `addBuffer()`\n>>    test: fence: Enable\n>>\n>>   .../guides/application-developer.rst          |    9 -\n>>   Documentation/guides/pipeline-handler.rst     |   10 +-\n>>   .../libhardware/include/hardware/camera3.h    |  360 +-\n>>   .../include/hardware/camera_common.h          |  304 +-\n>>   .../libhardware/include/hardware/gralloc.h    |   99 +-\n>>   .../android/metadata/camera_metadata_hidden.h |   11 +-\n>>   .../android/metadata/system/camera_metadata.h |   41 +-\n>>   .../metadata/system/camera_metadata_tags.h    |  633 +-\n>>   .../metadata/system/camera_vendor_tags.h      |   10 +-\n>>   .../android/system/core/include/android/log.h |  450 +-\n>>   .../core/include/cutils/native_handle.h       |   62 +-\n>>   .../system/core/include/system/camera.h       |    4 +-\n>>   .../core/include/system/graphics-base-v1.2.h  |   36 +\n>>   .../core/include/system/graphics-base.h       |    1 +\n>>   .../system/core/include/system/graphics.h     |   10 +-\n>>   include/libcamera/camera.h                    |    5 +-\n>>   include/libcamera/framebuffer.h               |    1 -\n>>   include/libcamera/internal/camera.h           |   46 +-\n>>   include/libcamera/internal/framebuffer.h      |    6 +\n>>   include/libcamera/internal/pipeline_handler.h |   31 +-\n>>   include/libcamera/internal/request.h          |   24 +-\n>>   include/libcamera/request.h                   |   10 +-\n>>   src/android/camera3_hal.cpp                   |    3 +\n>>   src/android/camera_capabilities.cpp           |    3 +\n>>   src/android/camera_device.cpp                 |  287 +-\n>>   src/android/camera_device.h                   |    4 +\n>>   src/android/camera_hal_manager.cpp            |    2 +-\n>>   src/android/camera_ops.cpp                    |   16 +-\n>>   src/android/camera_request.cpp                |   53 +-\n>>   src/android/camera_request.h                  |   11 +-\n>>   src/android/metadata/camera_metadata.c        |  183 +-\n>>   .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n>>   src/apps/cam/camera_session.cpp               |   36 +-\n>>   src/apps/cam/camera_session.h                 |    2 +-\n>>   src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n>>   src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n>>   src/apps/qcam/main_window.cpp                 |   82 +-\n>>   src/apps/qcam/main_window.h                   |    1 -\n>>   src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n>>   src/libcamera/camera.cpp                      |  164 +-\n>>   src/libcamera/fence.cpp                       |   15 +-\n>>   src/libcamera/framebuffer.cpp                 |   57 +-\n>>   src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n>>   src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n>>   src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n>>   src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n>>   src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n>>   src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n>>   .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n>>   .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n>>   src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n>>   src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n>>   src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n>>   src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n>>   src/libcamera/pipeline_handler.cpp            |  260 +-\n>>   src/libcamera/request.cpp                     |  290 +-\n>>   src/py/cam/cam.py                             |   20 +-\n>>   src/py/examples/simple-cam.py                 |   13 +-\n>>   src/py/examples/simple-capture.py             |   20 +-\n>>   src/py/examples/simple-continuous-capture.py  |   32 +-\n>>   src/py/libcamera/py_main.cpp                  |   65 +-\n>>   src/v4l2/v4l2_camera.cpp                      |  150 +-\n>>   src/v4l2/v4l2_camera.h                        |   25 +-\n>>   src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n>>   src/v4l2/v4l2_camera_proxy.h                  |    3 -\n>>   test/camera/buffer_import.cpp                 |   22 +-\n>>   test/camera/camera_reconfigure.cpp            |   22 +-\n>>   test/camera/capture.cpp                       |   24 +-\n>>   test/camera/statemachine.cpp                  |    4 +-\n>>   test/fence.cpp                                |  214 +-\n>>   70 files changed, 9182 insertions(+), 1283 deletions(-)\n>>   create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n>>\n>> --\n>> 2.54.0","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 B4FDFC328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  3 Jul 2026 14:37:53 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AEC0C65FC3;\n\tFri,  3 Jul 2026 16:37:52 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 8446265F9F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  3 Jul 2026 16:37:50 +0200 (CEST)","from [192.168.33.24] (185.221.140.128.nat.pool.zt.hu\n\t[185.221.140.128])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 50E6E1121;\n\tFri,  3 Jul 2026 16:37:04 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"TNtOPvmD\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1783089424;\n\tbh=S2hB1aA5t3/EcErf+j5fnLrj8rov/1ownw9bckBuLQQ=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=TNtOPvmDc5LWxGCDel9CziLe7+Ccf1RSvyhw7/8D2IlY+Uy7KJw8iH9eAyWA3SEYY\n\tbky+9yPmsD1aiuq2pWJl//xc76057rlLyu6AD0xCYlMJ1JduqUWOLC0W6+mmjQ6U62\n\t+YRGIun31gSUVkJj0vuksFgWv86H0EBPOcghncwM=","Message-ID":"<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>","Date":"Fri, 3 Jul 2026 16:37:45 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"David Plowman <david.plowman@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>\n\t<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39802,"web_url":"https://patchwork.libcamera.org/comment/39802/","msgid":"<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>","date":"2026-07-23T11:03:46","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"Hi Barnabas\n\nThanks for your replies.\n\nI think mostly I'm happy enough with things, though I wasn't quite\nclear why configure() has to empty the buffer pools (and you can't\nsimply leave stuff in them), I obviously haven't quite understood\nsomething there.\n\nThe Android doc that you linked to was interesting, and is definitely\nan improvement. I've been complaining about this \"targeting specific\nbuffers\" thing for years! It feels like libcamera will end up more\nlike Android once all this has been done. I note that Android appears\nto make no allowance for the\ncontrols-stuck-at-the-back-of-the-request-queue problem, so I'd be\ninterested to hear what folks think about that.\n\nFinally, is there any chance of getting any more visibility of the new\nAPI? In particular, seeing a minimal \"start-camera-and-request-frames\"\napplication might make it all feel a bit more concrete!\n\nThanks\nDavid\n\nOn Fri, 3 Jul 2026 at 15:37, Barnabás Pőcze\n<barnabas.pocze@ideasonboard.com> wrote:\n>\n> Hi\n>\n> I have tried to answer the questions, let me know if I'd missed anything.\n>\n> 2026. 07. 03. 14:37 keltezéssel, David Plowman írta:\n> > Hi Barnabas\n> >\n> > Thanks for working on all this, very excited to see progress on this topic!\n> >\n> > Unfortunately I'm about to disappear on holiday for 2 weeks, so this\n> > reply is going to turn into a long list of questions that I've not had\n> > a huge amount of time to think about, so apologies in advance for\n> > that.\n> >\n> > On Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n> > <barnabas.pocze@ideasonboard.com> wrote:\n> >>\n> >> This is the first RFC changeset for splitting requests and buffers. It largely\n> >> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n> >> already reviewed.\n> >>\n> >> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n> >>\n> >> ---\n> >>\n> >> # introduction\n> >>\n> >> The basic idea is that requests no longer have buffers when they are submitted,\n> >> and the camera keeps track of a set of buffers for each stream, and buffers will\n> >> be attached to requests from this pool in an unspecified order\n> >>\n> >> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n> >> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n> >> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n> >> is used to set which streams a request wants frames from.\n> >\n> > I guess I'm vaguely expecting the buffer pool mechanism to be to a\n> > large extent separate from the camera system. So the camera system\n> > will obviously be a client of it, but otherwise they're not really\n> > intertwined. Is that likely to be the case here? Or maybe it's not\n> > possible.\n>\n> The buffer pool mechanism is implemented in the \"Camera\" and related types.\n> And not in e.g. a separate `BufferPool` type. This was deemed the simpler\n> approach. But there are no technical obstacles as far as I can tell.\n> Or do you mean something else?\n>\n>\n> >\n> > I'm also vaguely feeling an application might want to control the\n> > lifetime of the pool and contents. For example, when the camera is\n> > stopped, maybe you want to leave your buffers in the pool so that you\n> > can simply restart it? Wasn't sure if that kind of behaviour is\n> > envisaged here.\n>\n> I don't think that option was discussed, but could be implemented.\n> Nonetheless then `configure()` has to clear the pool in any case,\n> which is technically a bit more complicated to do.\n>\n>\n> >\n> >>\n> >> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n> >> buffer for the given stream. If this buffer is not acceptable, then\n> >> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n> >> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n> >>\n> >> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n> >> the `PipelineHandler` base class fills each request with buffers before\n> >> calling `queueRequestDevice()`.\n> >\n> > One thing I raised a while back was whether there are applications\n> > that want to target specific buffers at particular requests. I'm\n> > thinking of Android here, though Android remains a giant mystery to\n> > me. But maybe another application might have a reason to do that?\n>\n> Android has caused quite a bit of headache, so in the end a switch\n> to their \"new\" buffer model was made: https://source.android.com/docs/core/camera/buffer-management-api\n>\n> This uses a similar pool based approach where requests no longer contain any buffers.\n>\n>\n> >\n> > The thought was to leave *optional* buffers in request. If it's there,\n> > you use it and otherwise the camera system goes to the buffer pool to\n> > get one. It sort of feels to me like it should be doable, but is it\n> > useful?\n> >\n> > I used to wonder whether an application might want to hold back a\n> > number of buffers so that it could do a burst capture, guaranteeing to\n> > have a buffer for every request. But I'm not so convinced by that,\n> > presumably you can check if you have enough buffers in the pool.\n> >\n> > Though having optional buffers would certainly ease migration to the new scheme!\n>\n> I don't have a satisfactory answer unfortunately. I think it's a matter\n> of making a decision, it seems technically feasible. Of course it would\n> complicate the core and pipeline handler parts.\n>\n> There is also a question of how to handle requests that mix both:\n> having some buffers and also some \"just\" enabled streams. Then\n> fences must also not be forgotten about. And then it has to be evaluated\n> how many technical difficulties supporting this mixed model would cause for\n> the existing pipeline handler implementations.\n>\n> An earlier prototype explored the idea of automatically adding buffers\n> from requests to the pool when they are queued. This of course would\n> break the association between buffers and requests, so it wouldn't\n> address your point. And it was decided not to go forward with this\n> compatibility behaviour in any case.\n>\n>\n> >\n> >>\n> >>\n> >> # discussion points\n> >>\n> >> ## adding buffers before `Camera::start()`\n> >>\n> >> Currently buffers can only be added in the \"Running\" state. They could\n> >> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n> >> and putting it into `stop()` would be a bit asymmetric.\n> >\n> > Indeed, I've always wanted to queue requests before starting the camera!\n> >\n> >>\n> >> ## empty pool notification\n> >>\n> >> Currently there is no mechanism for the application to know how many\n> >> buffers it should keep in the pool. I think a signal to notify the application\n> >> when it should add more buffers for a given stream could be added. But the\n> >> main idea was to expose some kind of minimum buffer count quantity.\n> >>\n> >> ## requirements towards application wrt. buffers\n> >>\n> >> With this prototype, an application is essentially required to always process *all*\n> >> buffers in *all* completed requests, otherwise it might lose buffers. (This\n> >> applies to cancelled requests as well.) Is that reasonable?\n> >\n> > I think it sounds OK to expect applications to manage buffers, at\n> > least to an extent. As I remarked above, I think maybe applications\n> > will want to manage buffers for their own convenience.\n> >\n> >>\n> >> ## returning unused buffers\n> >>\n> >> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n> >> where `request == nullptr`. This works, but may not be the best interface.\n> >>\n> >> ## returning rejected buffers\n> >>\n> >> Pipeline handlers can reject buffers. But how should that be signalled to the\n> >> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n> >> But this is not ideal because there isn't really a way to distinguish it from\n> >> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n> >> because `FrameError` requires some other fields to be valid.\n> >>\n> >> ## extending `completeBuffer()` with stream parameter\n> >>\n> >> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n> >> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n> >> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n> >> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n> >\n> > It does feel a bit strange to me that buffers should know about\n> > streams, and so on. I think I was expecting buffers/pools to be\n> > largely independent of such things. But I accept there might be a good\n> > reason.\n>\n> Indeed they shouldn't. But migrating straight to `completeBuffer(req, stream, buf)`\n> world where buffers have no idea about requests and streams\n> is not as simple as I would have liked. Especially since most\n> pipeline handlers are written with the current model in mind\n> where a buffer is already in a request associated with a stream.\n> And so the actual stream is not even easily available at buffer\n> completion time in many cases. So this is a compromise.\n>\n>\n> >\n> >>\n> >> ## fence timeout\n> >>\n> >> Previously a hard-coded timeout was used for fences. This is now removed.\n> >> Should there be a hard-coded fixed timeout for fences?\n> >>\n> >>\n> >> # TODO\n> >>\n> >> # converting more pipeline handlers\n> >>\n> >> Only the uvcvideo pipeline handler is converted to use the buffer pool\n> >> directly as an experiment, but more should be converted to really see\n> >> if this public api is a good fit for pipeline handlers. Especially something\n> >> like `imx8-isi` since that has a bit different architecture from the others.\n> >>\n> >> # minimum buffer count\n> >>\n> >> The applications need to know how many buffers should be kept in the pool\n> >> for a given stream for continuous streaming. This should be a property or\n> >> similar.\n> >\n> > Yes, I guess so. In practice we always allocate way more than the\n> > minimum, simply because that avoids frame drops.\n>\n> Yes, but this information can be useful if the buffer goes into a processing pipeline\n> that holds on to it, or if the applications creates its own `FrameBuffer`s without\n> the `FrameBufferAllocator`.\n>\n>\n> >\n> >>\n> >> # `FrameBuffer::Private::request()`\n> >>\n> >> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n> >> should probably be removed to fully decouple the two.\n> >\n> > One other slightly unusual use case I'd like to add into the mix is\n> > one I remember hearing on a Kamaros call. There's a stream of frames\n> > coming back from a camera, but then there's a second stream, made from\n> > the same sensor images, but which is generated only occasionally (so\n> > runs at a lower framerate).\n> >\n> > Does the buffer pool mechanism give us a way to handle this? When a\n> > request completes there could be 3 outcomes - 1. here's your buffer,\n> > 2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\n> > actually a frame generated for this stream on this occasion.\n>\n> You mean like a stream that might not supply a frame even if the\n> request enables it, there are available buffers, and no errors\n> are encountered? Or put differently, a stream that \"itself\" decides\n> when to supply frames regardless of the streams in the request?\n>\n> In that case currently (2) and (3) cannot be differentiated. But\n> it's a matter of extending the buffer map in the request.\n>\n>\n> >\n> > The final thing I'd like to discuss is how this relates to control\n> > queues. Of course, strictly speaking the two subjects are independent,\n> > but nonetheless I have a couple of questions.\n> >\n> > * The buffer/request split will obviously break the existing API and\n> > cause a certain amount of work. If we're going to have control queues,\n> > are we going to break everything again later, or do it all at once?\n> > Just wondering...\n>\n> I suppose it would be better to break the world once, but I'm no\n> authority on the question of libcamera stability and releases.\n>\n>\n> >\n> > * If you took control lists out of requests you might find there's\n> > almost nothing left in them. Wanted to check we're OK with that just\n> > in case we were to end up there!\n>\n> I think it's fine. A request would still have a \"cookie\" and the set\n> of enabled streams. And it has a sequence number, status, a set of\n> buffers, and a set of metadata items when it completes.\n>\n> Nonetheless we could explore getting rid of the application facing\n> `Request` type and using something different, maybe something more\n> centered around using the numeric sequence number as the identity.\n>\n>\n> >\n> > Anyway, apologies for the big dump of questions and then running away.\n> > Look forward to hearing more on the subject!\n> >\n> > Thanks\n> > David\n> >\n> >>\n> >> ---\n> >>\n> >> Barnabás Pőcze (54):\n> >>    apps: cam: Simplify buffer reuse\n> >>    libcamera: request: Disassociate buffer when cancelling\n> >>    libcamera: pipeline: Replace open-coded request cancellation\n> >>    libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n> >>    libcamera: pipeline: virtual: Make copy of request's buffer map\n> >>    libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n> >>    libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n> >>    v4l2: v4l2_camera: Avoid a level of indirection\n> >>    v4l2: v4l2_camera: Remove repated index checks\n> >>    v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n> >>    v4l2: v4l2_camera: Use actually allocated buffer count\n> >>    v4l2: v4l2_camera: Use buffer cookie for indexing\n> >>    v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n> >>    v4l2: v4l2_camera: Always clear pending requests\n> >>    v4l2: v4l2_camera: Clear completed requests when stopping\n> >>    v4l2: v4l2_camera: Provide buffers one by one\n> >>    test: fence: Disable temporarily\n> >>    libcamera: request: Remove `ReuseBuffers`\n> >>    libcamera: framebuffer: request(): Move to private type\n> >>    libcamera: framebuffer: Store associated Stream\n> >>    libcamera: camera: Add `StreamData`\n> >>    libcamera: camera: Add buffer pool\n> >>    libcamera: request: addBuffer(): Remove impl\n> >>    libcamera: request: Remove fence support\n> >>    libcamera: request: Store count of pending buffers\n> >>    libcamera: request: doCancelRequest(): Remove\n> >>    libcamera: pipeline_handler: Move constructor options to a separate\n> >>      type\n> >>    libcamera: pipeline_handler: Acquire buffers if not using pool\n> >>    libcamera: request: enableStream(): Add\n> >>    libcamera: camera: acquireBuffer(): Add\n> >>    libcamera: camera: rejectBuffer(): Add\n> >>    libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n> >>      function\n> >>    libcamera: pipeline_handler: Use `std::deque`\n> >>    libcamera: pipeline_handler: completeRequest(): Return request count\n> >>    libcamera: pipeline: uvcvideo: Use buffer pool prototype\n> >>    libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n> >>    libcamera: camera: bufferCompleted: Pass `Stream` as well\n> >>    libcamera: camera: queueRequest(): Adjust buffer map empty error\n> >>      message\n> >>    libcamera: camera: queueBuffer(): Reject if it has buffers\n> >>    apps: cam: Use camera buffer pool\n> >>    app: lc-compliance: Use camera buffer pool\n> >>    apps: lc-compliance: Add buffer pool tests\n> >>    test: Use camera buffer pool\n> >>    apps: qcam: Use camera buffer pool\n> >>    v4l2: Use camera buffer pool\n> >>    py: Use camera buffer pool\n> >>    gstreamer: Use camera buffer pool\n> >>    libcamera: request: Remove `ReuseFlag`\n> >>    android: Update imported files\n> >>    android: camera_request: Add helper for buffer conversion\n> >>    android: camera_device: Move fence restoration into\n> >>      `prepareToReturn()`\n> >>    android: Use camera buffer pool\n> >>    libcamera: request: Remove `addBuffer()`\n> >>    test: fence: Enable\n> >>\n> >>   .../guides/application-developer.rst          |    9 -\n> >>   Documentation/guides/pipeline-handler.rst     |   10 +-\n> >>   .../libhardware/include/hardware/camera3.h    |  360 +-\n> >>   .../include/hardware/camera_common.h          |  304 +-\n> >>   .../libhardware/include/hardware/gralloc.h    |   99 +-\n> >>   .../android/metadata/camera_metadata_hidden.h |   11 +-\n> >>   .../android/metadata/system/camera_metadata.h |   41 +-\n> >>   .../metadata/system/camera_metadata_tags.h    |  633 +-\n> >>   .../metadata/system/camera_vendor_tags.h      |   10 +-\n> >>   .../android/system/core/include/android/log.h |  450 +-\n> >>   .../core/include/cutils/native_handle.h       |   62 +-\n> >>   .../system/core/include/system/camera.h       |    4 +-\n> >>   .../core/include/system/graphics-base-v1.2.h  |   36 +\n> >>   .../core/include/system/graphics-base.h       |    1 +\n> >>   .../system/core/include/system/graphics.h     |   10 +-\n> >>   include/libcamera/camera.h                    |    5 +-\n> >>   include/libcamera/framebuffer.h               |    1 -\n> >>   include/libcamera/internal/camera.h           |   46 +-\n> >>   include/libcamera/internal/framebuffer.h      |    6 +\n> >>   include/libcamera/internal/pipeline_handler.h |   31 +-\n> >>   include/libcamera/internal/request.h          |   24 +-\n> >>   include/libcamera/request.h                   |   10 +-\n> >>   src/android/camera3_hal.cpp                   |    3 +\n> >>   src/android/camera_capabilities.cpp           |    3 +\n> >>   src/android/camera_device.cpp                 |  287 +-\n> >>   src/android/camera_device.h                   |    4 +\n> >>   src/android/camera_hal_manager.cpp            |    2 +-\n> >>   src/android/camera_ops.cpp                    |   16 +-\n> >>   src/android/camera_request.cpp                |   53 +-\n> >>   src/android/camera_request.h                  |   11 +-\n> >>   src/android/metadata/camera_metadata.c        |  183 +-\n> >>   .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n> >>   src/apps/cam/camera_session.cpp               |   36 +-\n> >>   src/apps/cam/camera_session.h                 |    2 +-\n> >>   src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n> >>   src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n> >>   src/apps/qcam/main_window.cpp                 |   82 +-\n> >>   src/apps/qcam/main_window.h                   |    1 -\n> >>   src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n> >>   src/libcamera/camera.cpp                      |  164 +-\n> >>   src/libcamera/fence.cpp                       |   15 +-\n> >>   src/libcamera/framebuffer.cpp                 |   57 +-\n> >>   src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n> >>   src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n> >>   src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n> >>   src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n> >>   src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n> >>   src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n> >>   .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n> >>   .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n> >>   src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n> >>   src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n> >>   src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n> >>   src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n> >>   src/libcamera/pipeline_handler.cpp            |  260 +-\n> >>   src/libcamera/request.cpp                     |  290 +-\n> >>   src/py/cam/cam.py                             |   20 +-\n> >>   src/py/examples/simple-cam.py                 |   13 +-\n> >>   src/py/examples/simple-capture.py             |   20 +-\n> >>   src/py/examples/simple-continuous-capture.py  |   32 +-\n> >>   src/py/libcamera/py_main.cpp                  |   65 +-\n> >>   src/v4l2/v4l2_camera.cpp                      |  150 +-\n> >>   src/v4l2/v4l2_camera.h                        |   25 +-\n> >>   src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n> >>   src/v4l2/v4l2_camera_proxy.h                  |    3 -\n> >>   test/camera/buffer_import.cpp                 |   22 +-\n> >>   test/camera/camera_reconfigure.cpp            |   22 +-\n> >>   test/camera/capture.cpp                       |   24 +-\n> >>   test/camera/statemachine.cpp                  |    4 +-\n> >>   test/fence.cpp                                |  214 +-\n> >>   70 files changed, 9182 insertions(+), 1283 deletions(-)\n> >>   create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n> >>\n> >> --\n> >> 2.54.0\n>","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 A5757C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 23 Jul 2026 11:04:00 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4DE7767EB4;\n\tThu, 23 Jul 2026 13:03:59 +0200 (CEST)","from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com\n\t[IPv6:2a00:1450:4864:20::52d])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 98DBE67E5C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Jul 2026 13:03:58 +0200 (CEST)","by mail-ed1-x52d.google.com with SMTP id\n\t4fb4d7f45d1cf-6986287534eso952180a12.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Jul 2026 04:03:58 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"jzrmE8tt\"; dkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1784804638; cv=none;\n\td=google.com; s=arc-20260327;\n\tb=eldEiAgVifkqOaXwuHcTOpBles/BWeJSGAWnFWLYLYsMPGJG6L3kgILCtVCzPUrf+t\n\tT39qtUiu1A28IE5/knRVLFROioVNVN50XKsxj9RhpDjZUllVGznW+/lnmTBic/4LKymg\n\t1gc2H+YNFPE/JyHMsolqOiJHk7dZ64GZxsBgeGcGz2OD9CZPp4JYJmpb+20ccVjTCYIL\n\tK0Bt3YlEpESaO4JtUpdEr60caA5H+d8F2sXweviII4OL6vowkZFrqngJKY4K+D2jja+W\n\t1js+w+5OpSQQJSX7R0SntA+MJplyQgMCNlfszZMzeEmHQgDqKm5rkYY7zW3vw9Q1mN6I\n\tN16A==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n\ts=arc-20260327; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:dkim-signature;\n\tbh=xlwz9U3Dk63gN+7gyCF/kb5Evr3V8ZVXPHv8fmjZ9zc=;\n\tfh=6eMZ9Peh5oKJMXVlU5do7GxLXGl0cSCd64pkjvWpyo4=;\n\tb=sK6AmvLsaPSRGqFDAHeWJX695DmWaZyElgQrKdUs/N+UtWucyuB7GhPvfUeI99TW7I\n\tWEHRb69yjaj06OO/9xGRXKRv5NHvlbCHkpXA8IEuD8rAT2E7hSCQKBvey6+dUzCg3/QM\n\tlKFekgWr5Bbkpilfobt84L2JFVDgmz/qE/eEAuYfFIrdMKOeuDat7v8GXpSaZzfh2Xat\n\tNlJyB8DqE10qL62/5lt0wEgSC71Liokxjlor4hsgop6nDaT/od4BTLNAekfB/4fDaJFM\n\tWYwz6rZ4RkPQrlxPmahuryDglX/9E/F2cOOv5rxXyinClqJb7pHbFRKLuNKupsXdIBWq\n\tQg6Q==; darn=lists.libcamera.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1784804638; x=1785409438;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:from:to:cc:subject\n\t:date:message-id:reply-to:content-type;\n\tbh=xlwz9U3Dk63gN+7gyCF/kb5Evr3V8ZVXPHv8fmjZ9zc=;\n\tb=jzrmE8ttKYi5hGVwOurCyUVtOyeYZ3WNJuIAObp/50U6Y+eaxXnmhOYfKUW+H8EQmL\n\tnckskjTGw6XRyDocceRJWhcnZcPNx2DjeTx9RhHLC0N1RTcbfOEo4VAYRR1qAwq4F/GV\n\tLQ9egK6oCXaFXaSbGishOrcQ0Gb9UytxBDNDbmpAueL800y0fQE/0WTjE3/2W7QC40pg\n\ttdPkY+2vEscInY/YoE6B2ahRtjyaS2C8CCzLoNcc6gWOl+Du0gwVr9hTthienBZhI9GL\n\toySN3VDtOFHersA0FmmIzePifwbgc/2rlxPnAtk81RMKfoa7GPJZH22AADKYAVG4rlD8\n\t8GsQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784804638; x=1785409438;\n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to\n\t:content-type;\n\tbh=xlwz9U3Dk63gN+7gyCF/kb5Evr3V8ZVXPHv8fmjZ9zc=;\n\tb=Tz8Uqku/C190xVWJXDUKqvQwWQY+xnd+ILNNRnXv3LNNEd2dWUkflShjVysPbpoiqQ\n\tmdTYLaOWYp7xkag+pjoEnF5R4LauCFl8PNkd3vRtAUX4jbozn1sp4BFFQnE7uv3v/SiV\n\tnD6upVHJWpCdKfAugfHfD/ihytbIUkv4TK6uymx8fYMUj3R6r3jOttZc3w8/CpGRQRew\n\tsYk6+X7yuvpzcpDNQMI15GZ+MPrOh3S3J68n25jqRUD4zFk7wb17DOJ0uTZS3LbqQtMG\n\t8a2+Spjgr+4jgFPA6643hLgHQNIj+c9/50qgBPmj2xphhWVrQ4BeG9tQ+KsSQRWlgO7w\n\tDqmg==","X-Gm-Message-State":"AOJu0YwANN/Gyu5+ZlWDGexnxZk9jUqWuLuMgLNXil6E7epfnVb37UW0\n\tVYOX+ewhCSE2rTMXpz9YMvNG4yzpSI/TWLZYjyptju+0Hb3E0mzD4LG4oqMNzZzFUkF5X76MWud\n\tnmYHn2muueHo4PUGrmeTVQrYx6ioBlRw1XRtYZtqeEA==","X-Gm-Gg":"AR+sD13jTfxACs/vgNpfU0ovWyo6rhSVAtbva4IHL3at4PNjKDBvLYk/inpfRqmFm2o\n\tufT0z3846hnKySdrsvsMqNs3UpKfovx5hcRPgebAdOO67ADYpIIhBGUVuSZNv6pa3iWvZ+Lcs1A\n\ttS1uwLmvYV67F0/BUpW6URfpY6tFI8zaHgDjkLXZ159XVZA5FxkICGyG6YSp5BdB1opLOtKR1bV\n\tOLHM5cd4BuJbp504tFRs9se1lAI9qPpVS7Q+XLi7mmPagg6z9nMEr9PY5XvxZ288NnimC79EGUU\n\t3GyoPIyA/VFd260RQ/GUIZjQKfFShz2BlhkO55pmUiLEQnWMPIgXezhPTb5pssBhqMSkS2D/iK7\n\tfKxk=","X-Received":"by 2002:a05:6402:3584:b0:698:aa8c:c15e with SMTP id\n\t4fb4d7f45d1cf-69f6d8de5dbmr1122941a12.25.1784804637661;\n\tThu, 23 Jul 2026 04:03:57 -0700 (PDT)","MIME-Version":"1.0","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>\n\t<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>\n\t<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>","In-Reply-To":"<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Thu, 23 Jul 2026 12:03:46 +0100","X-Gm-Features":"AUfX_mzUUWTiRsSy8-QyN-6d3GlajUYcwXbNzlKAUrzx_56qoKdGup9Tsgxf9vw","Message-ID":"<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39810,"web_url":"https://patchwork.libcamera.org/comment/39810/","msgid":"<52279d34-59ec-4e62-b82b-04a40b784b41@ideasonboard.com>","date":"2026-07-23T15:42:14","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2026. 07. 23. 13:03 keltezéssel, David Plowman írta:\n> Hi Barnabas\n> \n> Thanks for your replies.\n> \n> I think mostly I'm happy enough with things, though I wasn't quite\n> clear why configure() has to empty the buffer pools (and you can't\n> simply leave stuff in them), I obviously haven't quite understood\n> something there.\n\nThe thinking is that configuration most likely changes the size of the\nresulting images, so leaving buffers that were created with the previous\nconfiguration in mind could be problematic. It's simpler to just always\nensure that the pool is empty after configuration.\n\n\n> \n> The Android doc that you linked to was interesting, and is definitely\n> an improvement. I've been complaining about this \"targeting specific\n> buffers\" thing for years! It feels like libcamera will end up more\n> like Android once all this has been done. I note that Android appears\n> to make no allowance for the\n> controls-stuck-at-the-back-of-the-request-queue problem, so I'd be\n> interested to hear what folks think about that.\n> \n> Finally, is there any chance of getting any more visibility of the new\n> API? In particular, seeing a minimal \"start-camera-and-request-frames\"\n> application might make it all feel a bit more concrete!\n\nMost things remain the same, the main conceptual difference is that\n`Camera::addBuffer()` needs to be called to provide the buffers,\nand the targeted streams must be explicitly enabled in a request\nwith `Request::enableStream()`\n\nThe most straightforward way to convert an application would be something like this:\n   * replace `Request::addBuffer()` with a combination of:\n     - `Camera::addBuffer()`\n     - `Request::enableStream()`\n   * replace `Request::reuse(ReuseBuffers)` with a combination of:\n     - `Camera::addBuffer()` for each buffer in the request\n     - `Request::reuse()`\n     - `Request::enableStream()` for each target stream\n\nI believe patch \"py: Use camera buffer pool\" (especially src/py/examples/simple-cam.py)\nshould showcase the minimal \"start-camera-and-request-frames\" application\nyou're looking for (albeit in python, not C++). But let me know if you need a better example.\nIn any case, if the details of the API are finalized, https://gitlab.freedesktop.org/camera/simple-cam\nwill be updated to reflect the changes.\n\nThe only complication is that `Camera::addBuffer()` is only allowed after `Camera::start()`.\nAnd there are some unsure details still, specifically related to how buffers\ncan / cannot be returned without a request (i.e. how can a pipeline handler\n\"reject\" a buffer and how can the application recognize that).\n\n\nRegards,\nBarnabás Pőcze\n\n> \n> Thanks\n> David\n> \n> On Fri, 3 Jul 2026 at 15:37, Barnabás Pőcze\n> <barnabas.pocze@ideasonboard.com> wrote:\n>>\n>> Hi\n>>\n>> I have tried to answer the questions, let me know if I'd missed anything.\n>>\n>> 2026. 07. 03. 14:37 keltezéssel, David Plowman írta:\n>>> Hi Barnabas\n>>>\n>>> Thanks for working on all this, very excited to see progress on this topic!\n>>>\n>>> Unfortunately I'm about to disappear on holiday for 2 weeks, so this\n>>> reply is going to turn into a long list of questions that I've not had\n>>> a huge amount of time to think about, so apologies in advance for\n>>> that.\n>>>\n>>> On Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n>>> <barnabas.pocze@ideasonboard.com> wrote:\n>>>>\n>>>> This is the first RFC changeset for splitting requests and buffers. It largely\n>>>> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n>>>> already reviewed.\n>>>>\n>>>> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n>>>>\n>>>> ---\n>>>>\n>>>> # introduction\n>>>>\n>>>> The basic idea is that requests no longer have buffers when they are submitted,\n>>>> and the camera keeps track of a set of buffers for each stream, and buffers will\n>>>> be attached to requests from this pool in an unspecified order\n>>>>\n>>>> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n>>>> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n>>>> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n>>>> is used to set which streams a request wants frames from.\n>>>\n>>> I guess I'm vaguely expecting the buffer pool mechanism to be to a\n>>> large extent separate from the camera system. So the camera system\n>>> will obviously be a client of it, but otherwise they're not really\n>>> intertwined. Is that likely to be the case here? Or maybe it's not\n>>> possible.\n>>\n>> The buffer pool mechanism is implemented in the \"Camera\" and related types.\n>> And not in e.g. a separate `BufferPool` type. This was deemed the simpler\n>> approach. But there are no technical obstacles as far as I can tell.\n>> Or do you mean something else?\n>>\n>>\n>>>\n>>> I'm also vaguely feeling an application might want to control the\n>>> lifetime of the pool and contents. For example, when the camera is\n>>> stopped, maybe you want to leave your buffers in the pool so that you\n>>> can simply restart it? Wasn't sure if that kind of behaviour is\n>>> envisaged here.\n>>\n>> I don't think that option was discussed, but could be implemented.\n>> Nonetheless then `configure()` has to clear the pool in any case,\n>> which is technically a bit more complicated to do.\n>>\n>>\n>>>\n>>>>\n>>>> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n>>>> buffer for the given stream. If this buffer is not acceptable, then\n>>>> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n>>>> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n>>>>\n>>>> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n>>>> the `PipelineHandler` base class fills each request with buffers before\n>>>> calling `queueRequestDevice()`.\n>>>\n>>> One thing I raised a while back was whether there are applications\n>>> that want to target specific buffers at particular requests. I'm\n>>> thinking of Android here, though Android remains a giant mystery to\n>>> me. But maybe another application might have a reason to do that?\n>>\n>> Android has caused quite a bit of headache, so in the end a switch\n>> to their \"new\" buffer model was made: https://source.android.com/docs/core/camera/buffer-management-api\n>>\n>> This uses a similar pool based approach where requests no longer contain any buffers.\n>>\n>>\n>>>\n>>> The thought was to leave *optional* buffers in request. If it's there,\n>>> you use it and otherwise the camera system goes to the buffer pool to\n>>> get one. It sort of feels to me like it should be doable, but is it\n>>> useful?\n>>>\n>>> I used to wonder whether an application might want to hold back a\n>>> number of buffers so that it could do a burst capture, guaranteeing to\n>>> have a buffer for every request. But I'm not so convinced by that,\n>>> presumably you can check if you have enough buffers in the pool.\n>>>\n>>> Though having optional buffers would certainly ease migration to the new scheme!\n>>\n>> I don't have a satisfactory answer unfortunately. I think it's a matter\n>> of making a decision, it seems technically feasible. Of course it would\n>> complicate the core and pipeline handler parts.\n>>\n>> There is also a question of how to handle requests that mix both:\n>> having some buffers and also some \"just\" enabled streams. Then\n>> fences must also not be forgotten about. And then it has to be evaluated\n>> how many technical difficulties supporting this mixed model would cause for\n>> the existing pipeline handler implementations.\n>>\n>> An earlier prototype explored the idea of automatically adding buffers\n>> from requests to the pool when they are queued. This of course would\n>> break the association between buffers and requests, so it wouldn't\n>> address your point. And it was decided not to go forward with this\n>> compatibility behaviour in any case.\n>>\n>>\n>>>\n>>>>\n>>>>\n>>>> # discussion points\n>>>>\n>>>> ## adding buffers before `Camera::start()`\n>>>>\n>>>> Currently buffers can only be added in the \"Running\" state. They could\n>>>> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n>>>> and putting it into `stop()` would be a bit asymmetric.\n>>>\n>>> Indeed, I've always wanted to queue requests before starting the camera!\n>>>\n>>>>\n>>>> ## empty pool notification\n>>>>\n>>>> Currently there is no mechanism for the application to know how many\n>>>> buffers it should keep in the pool. I think a signal to notify the application\n>>>> when it should add more buffers for a given stream could be added. But the\n>>>> main idea was to expose some kind of minimum buffer count quantity.\n>>>>\n>>>> ## requirements towards application wrt. buffers\n>>>>\n>>>> With this prototype, an application is essentially required to always process *all*\n>>>> buffers in *all* completed requests, otherwise it might lose buffers. (This\n>>>> applies to cancelled requests as well.) Is that reasonable?\n>>>\n>>> I think it sounds OK to expect applications to manage buffers, at\n>>> least to an extent. As I remarked above, I think maybe applications\n>>> will want to manage buffers for their own convenience.\n>>>\n>>>>\n>>>> ## returning unused buffers\n>>>>\n>>>> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n>>>> where `request == nullptr`. This works, but may not be the best interface.\n>>>>\n>>>> ## returning rejected buffers\n>>>>\n>>>> Pipeline handlers can reject buffers. But how should that be signalled to the\n>>>> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n>>>> But this is not ideal because there isn't really a way to distinguish it from\n>>>> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n>>>> because `FrameError` requires some other fields to be valid.\n>>>>\n>>>> ## extending `completeBuffer()` with stream parameter\n>>>>\n>>>> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n>>>> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n>>>> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n>>>> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n>>>\n>>> It does feel a bit strange to me that buffers should know about\n>>> streams, and so on. I think I was expecting buffers/pools to be\n>>> largely independent of such things. But I accept there might be a good\n>>> reason.\n>>\n>> Indeed they shouldn't. But migrating straight to `completeBuffer(req, stream, buf)`\n>> world where buffers have no idea about requests and streams\n>> is not as simple as I would have liked. Especially since most\n>> pipeline handlers are written with the current model in mind\n>> where a buffer is already in a request associated with a stream.\n>> And so the actual stream is not even easily available at buffer\n>> completion time in many cases. So this is a compromise.\n>>\n>>\n>>>\n>>>>\n>>>> ## fence timeout\n>>>>\n>>>> Previously a hard-coded timeout was used for fences. This is now removed.\n>>>> Should there be a hard-coded fixed timeout for fences?\n>>>>\n>>>>\n>>>> # TODO\n>>>>\n>>>> # converting more pipeline handlers\n>>>>\n>>>> Only the uvcvideo pipeline handler is converted to use the buffer pool\n>>>> directly as an experiment, but more should be converted to really see\n>>>> if this public api is a good fit for pipeline handlers. Especially something\n>>>> like `imx8-isi` since that has a bit different architecture from the others.\n>>>>\n>>>> # minimum buffer count\n>>>>\n>>>> The applications need to know how many buffers should be kept in the pool\n>>>> for a given stream for continuous streaming. This should be a property or\n>>>> similar.\n>>>\n>>> Yes, I guess so. In practice we always allocate way more than the\n>>> minimum, simply because that avoids frame drops.\n>>\n>> Yes, but this information can be useful if the buffer goes into a processing pipeline\n>> that holds on to it, or if the applications creates its own `FrameBuffer`s without\n>> the `FrameBufferAllocator`.\n>>\n>>\n>>>\n>>>>\n>>>> # `FrameBuffer::Private::request()`\n>>>>\n>>>> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n>>>> should probably be removed to fully decouple the two.\n>>>\n>>> One other slightly unusual use case I'd like to add into the mix is\n>>> one I remember hearing on a Kamaros call. There's a stream of frames\n>>> coming back from a camera, but then there's a second stream, made from\n>>> the same sensor images, but which is generated only occasionally (so\n>>> runs at a lower framerate).\n>>>\n>>> Does the buffer pool mechanism give us a way to handle this? When a\n>>> request completes there could be 3 outcomes - 1. here's your buffer,\n>>> 2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\n>>> actually a frame generated for this stream on this occasion.\n>>\n>> You mean like a stream that might not supply a frame even if the\n>> request enables it, there are available buffers, and no errors\n>> are encountered? Or put differently, a stream that \"itself\" decides\n>> when to supply frames regardless of the streams in the request?\n>>\n>> In that case currently (2) and (3) cannot be differentiated. But\n>> it's a matter of extending the buffer map in the request.\n>>\n>>\n>>>\n>>> The final thing I'd like to discuss is how this relates to control\n>>> queues. Of course, strictly speaking the two subjects are independent,\n>>> but nonetheless I have a couple of questions.\n>>>\n>>> * The buffer/request split will obviously break the existing API and\n>>> cause a certain amount of work. If we're going to have control queues,\n>>> are we going to break everything again later, or do it all at once?\n>>> Just wondering...\n>>\n>> I suppose it would be better to break the world once, but I'm no\n>> authority on the question of libcamera stability and releases.\n>>\n>>\n>>>\n>>> * If you took control lists out of requests you might find there's\n>>> almost nothing left in them. Wanted to check we're OK with that just\n>>> in case we were to end up there!\n>>\n>> I think it's fine. A request would still have a \"cookie\" and the set\n>> of enabled streams. And it has a sequence number, status, a set of\n>> buffers, and a set of metadata items when it completes.\n>>\n>> Nonetheless we could explore getting rid of the application facing\n>> `Request` type and using something different, maybe something more\n>> centered around using the numeric sequence number as the identity.\n>>\n>>\n>>>\n>>> Anyway, apologies for the big dump of questions and then running away.\n>>> Look forward to hearing more on the subject!\n>>>\n>>> Thanks\n>>> David\n>>>\n>>>>\n>>>> ---\n>>>>\n>>>> Barnabás Pőcze (54):\n>>>>     apps: cam: Simplify buffer reuse\n>>>>     libcamera: request: Disassociate buffer when cancelling\n>>>>     libcamera: pipeline: Replace open-coded request cancellation\n>>>>     libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n>>>>     libcamera: pipeline: virtual: Make copy of request's buffer map\n>>>>     libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n>>>>     libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n>>>>     v4l2: v4l2_camera: Avoid a level of indirection\n>>>>     v4l2: v4l2_camera: Remove repated index checks\n>>>>     v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n>>>>     v4l2: v4l2_camera: Use actually allocated buffer count\n>>>>     v4l2: v4l2_camera: Use buffer cookie for indexing\n>>>>     v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n>>>>     v4l2: v4l2_camera: Always clear pending requests\n>>>>     v4l2: v4l2_camera: Clear completed requests when stopping\n>>>>     v4l2: v4l2_camera: Provide buffers one by one\n>>>>     test: fence: Disable temporarily\n>>>>     libcamera: request: Remove `ReuseBuffers`\n>>>>     libcamera: framebuffer: request(): Move to private type\n>>>>     libcamera: framebuffer: Store associated Stream\n>>>>     libcamera: camera: Add `StreamData`\n>>>>     libcamera: camera: Add buffer pool\n>>>>     libcamera: request: addBuffer(): Remove impl\n>>>>     libcamera: request: Remove fence support\n>>>>     libcamera: request: Store count of pending buffers\n>>>>     libcamera: request: doCancelRequest(): Remove\n>>>>     libcamera: pipeline_handler: Move constructor options to a separate\n>>>>       type\n>>>>     libcamera: pipeline_handler: Acquire buffers if not using pool\n>>>>     libcamera: request: enableStream(): Add\n>>>>     libcamera: camera: acquireBuffer(): Add\n>>>>     libcamera: camera: rejectBuffer(): Add\n>>>>     libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n>>>>       function\n>>>>     libcamera: pipeline_handler: Use `std::deque`\n>>>>     libcamera: pipeline_handler: completeRequest(): Return request count\n>>>>     libcamera: pipeline: uvcvideo: Use buffer pool prototype\n>>>>     libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n>>>>     libcamera: camera: bufferCompleted: Pass `Stream` as well\n>>>>     libcamera: camera: queueRequest(): Adjust buffer map empty error\n>>>>       message\n>>>>     libcamera: camera: queueBuffer(): Reject if it has buffers\n>>>>     apps: cam: Use camera buffer pool\n>>>>     app: lc-compliance: Use camera buffer pool\n>>>>     apps: lc-compliance: Add buffer pool tests\n>>>>     test: Use camera buffer pool\n>>>>     apps: qcam: Use camera buffer pool\n>>>>     v4l2: Use camera buffer pool\n>>>>     py: Use camera buffer pool\n>>>>     gstreamer: Use camera buffer pool\n>>>>     libcamera: request: Remove `ReuseFlag`\n>>>>     android: Update imported files\n>>>>     android: camera_request: Add helper for buffer conversion\n>>>>     android: camera_device: Move fence restoration into\n>>>>       `prepareToReturn()`\n>>>>     android: Use camera buffer pool\n>>>>     libcamera: request: Remove `addBuffer()`\n>>>>     test: fence: Enable\n>>>>\n>>>>    .../guides/application-developer.rst          |    9 -\n>>>>    Documentation/guides/pipeline-handler.rst     |   10 +-\n>>>>    .../libhardware/include/hardware/camera3.h    |  360 +-\n>>>>    .../include/hardware/camera_common.h          |  304 +-\n>>>>    .../libhardware/include/hardware/gralloc.h    |   99 +-\n>>>>    .../android/metadata/camera_metadata_hidden.h |   11 +-\n>>>>    .../android/metadata/system/camera_metadata.h |   41 +-\n>>>>    .../metadata/system/camera_metadata_tags.h    |  633 +-\n>>>>    .../metadata/system/camera_vendor_tags.h      |   10 +-\n>>>>    .../android/system/core/include/android/log.h |  450 +-\n>>>>    .../core/include/cutils/native_handle.h       |   62 +-\n>>>>    .../system/core/include/system/camera.h       |    4 +-\n>>>>    .../core/include/system/graphics-base-v1.2.h  |   36 +\n>>>>    .../core/include/system/graphics-base.h       |    1 +\n>>>>    .../system/core/include/system/graphics.h     |   10 +-\n>>>>    include/libcamera/camera.h                    |    5 +-\n>>>>    include/libcamera/framebuffer.h               |    1 -\n>>>>    include/libcamera/internal/camera.h           |   46 +-\n>>>>    include/libcamera/internal/framebuffer.h      |    6 +\n>>>>    include/libcamera/internal/pipeline_handler.h |   31 +-\n>>>>    include/libcamera/internal/request.h          |   24 +-\n>>>>    include/libcamera/request.h                   |   10 +-\n>>>>    src/android/camera3_hal.cpp                   |    3 +\n>>>>    src/android/camera_capabilities.cpp           |    3 +\n>>>>    src/android/camera_device.cpp                 |  287 +-\n>>>>    src/android/camera_device.h                   |    4 +\n>>>>    src/android/camera_hal_manager.cpp            |    2 +-\n>>>>    src/android/camera_ops.cpp                    |   16 +-\n>>>>    src/android/camera_request.cpp                |   53 +-\n>>>>    src/android/camera_request.h                  |   11 +-\n>>>>    src/android/metadata/camera_metadata.c        |  183 +-\n>>>>    .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n>>>>    src/apps/cam/camera_session.cpp               |   36 +-\n>>>>    src/apps/cam/camera_session.h                 |    2 +-\n>>>>    src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n>>>>    src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n>>>>    src/apps/qcam/main_window.cpp                 |   82 +-\n>>>>    src/apps/qcam/main_window.h                   |    1 -\n>>>>    src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n>>>>    src/libcamera/camera.cpp                      |  164 +-\n>>>>    src/libcamera/fence.cpp                       |   15 +-\n>>>>    src/libcamera/framebuffer.cpp                 |   57 +-\n>>>>    src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n>>>>    src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n>>>>    src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n>>>>    src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n>>>>    src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n>>>>    src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n>>>>    .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n>>>>    .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n>>>>    src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n>>>>    src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n>>>>    src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n>>>>    src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n>>>>    src/libcamera/pipeline_handler.cpp            |  260 +-\n>>>>    src/libcamera/request.cpp                     |  290 +-\n>>>>    src/py/cam/cam.py                             |   20 +-\n>>>>    src/py/examples/simple-cam.py                 |   13 +-\n>>>>    src/py/examples/simple-capture.py             |   20 +-\n>>>>    src/py/examples/simple-continuous-capture.py  |   32 +-\n>>>>    src/py/libcamera/py_main.cpp                  |   65 +-\n>>>>    src/v4l2/v4l2_camera.cpp                      |  150 +-\n>>>>    src/v4l2/v4l2_camera.h                        |   25 +-\n>>>>    src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n>>>>    src/v4l2/v4l2_camera_proxy.h                  |    3 -\n>>>>    test/camera/buffer_import.cpp                 |   22 +-\n>>>>    test/camera/camera_reconfigure.cpp            |   22 +-\n>>>>    test/camera/capture.cpp                       |   24 +-\n>>>>    test/camera/statemachine.cpp                  |    4 +-\n>>>>    test/fence.cpp                                |  214 +-\n>>>>    70 files changed, 9182 insertions(+), 1283 deletions(-)\n>>>>    create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n>>>>\n>>>> --\n>>>> 2.54.0\n>>","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 C288DBDE17\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 23 Jul 2026 15:42:19 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A91D967EBA;\n\tThu, 23 Jul 2026 17:42:18 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BA78B67E5C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Jul 2026 17:42:17 +0200 (CEST)","from [192.168.33.41] (185.182.215.156.nat.pool.zt.hu\n\t[185.182.215.156])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 797961C37;\n\tThu, 23 Jul 2026 17:41:16 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"n1xBr6Ab\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1784821276;\n\tbh=nnxiiZTEluWixFa4RAdxi0dN1wuUm2xNxr5yYyQM2fk=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=n1xBr6AbcHF78hTwdf3fhHPPzD/9ZwUKqfxPKemYi0LXnngeUu4CK9uSUxNJEFEP3\n\te7+z8ps0Lt9jxLwFFeVbQW1yWHz2AIOJbRe4uFhR11WOHcMNhiTP9DEk0u6Uc0Nn0i\n\tdmnil2xRosz2C/w+v/inVz8a9cquhGwxsDm9dEek=","Message-ID":"<52279d34-59ec-4e62-b82b-04a40b784b41@ideasonboard.com>","Date":"Thu, 23 Jul 2026 17:42:14 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"David Plowman <david.plowman@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>\n\t<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>\n\t<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>\n\t<6tLdsPxodLNz3BDMEKU1_ZOQefpKwKapmLdAYPy8mlyZoh2gLSJF0_niM_9SMUK1C-zBMyPOFhMvo0PWN_ib7A==@protonmail.internalid>\n\t<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39819,"web_url":"https://patchwork.libcamera.org/comment/39819/","msgid":"<CAHW6GYJna1S=1cP96O+MSUTCOhvYi_VRA62+xXUXr_JvhVZzJw@mail.gmail.com>","date":"2026-07-24T12:02:48","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"Hi again\n\nSorry for asking another question!\n\nOn Thu, 23 Jul 2026 at 16:42, Barnabás Pőcze\n<barnabas.pocze@ideasonboard.com> wrote:\n>\n> Hi\n>\n> 2026. 07. 23. 13:03 keltezéssel, David Plowman írta:\n> > Hi Barnabas\n> >\n> > Thanks for your replies.\n> >\n> > I think mostly I'm happy enough with things, though I wasn't quite\n> > clear why configure() has to empty the buffer pools (and you can't\n> > simply leave stuff in them), I obviously haven't quite understood\n> > something there.\n>\n> The thinking is that configuration most likely changes the size of the\n> resulting images, so leaving buffers that were created with the previous\n> configuration in mind could be problematic. It's simpler to just always\n> ensure that the pool is empty after configuration.\n>\n>\n> >\n> > The Android doc that you linked to was interesting, and is definitely\n> > an improvement. I've been complaining about this \"targeting specific\n> > buffers\" thing for years! It feels like libcamera will end up more\n> > like Android once all this has been done. I note that Android appears\n> > to make no allowance for the\n> > controls-stuck-at-the-back-of-the-request-queue problem, so I'd be\n> > interested to hear what folks think about that.\n> >\n> > Finally, is there any chance of getting any more visibility of the new\n> > API? In particular, seeing a minimal \"start-camera-and-request-frames\"\n> > application might make it all feel a bit more concrete!\n>\n> Most things remain the same, the main conceptual difference is that\n> `Camera::addBuffer()` needs to be called to provide the buffers,\n> and the targeted streams must be explicitly enabled in a request\n> with `Request::enableStream()`\n\nSomething was bothering me a bit here, and it finally dawned on me what it was.\n\nIn the Android world, where control lists are synchronised with the\nrequest you put them in, this seems fine.\n\nHowever, if you want to be able to send control lists that bypass the\nrequest queue, then you have no way to synchronise the enabling of a\nbuffer with that control list.\n\nSo the most obvious example is if I'm running with, say, 16 requests\ncirculating, because I have a Pi that's busy or slow and I don't want\nto drop frames. Now I want to do a capture with exposure X and enable\na buffer for my high resolution stream for that capture (for which I\nam not normally enabling buffers). I have no way to send my control\n\"early\" and enable a buffer for it. (Instead, the whole system would\nbe forced to work in \"Android mode\", and you'd have to submit a\nrequest and wait 16 frames for your buffer to arrive. Ouch!)\n\nThe obvious answer would seem to be that enabling buffers should be a\ncontrol. In the Android world that would work just the same, because\nthey're synchronised, but it would also enable the use case above\nthat's important to us. Or one could let applications do it either\nway, I suppose.\n\nAny thoughts?\n\nThanks!\nDavid\n\n>\n> The most straightforward way to convert an application would be something like this:\n>    * replace `Request::addBuffer()` with a combination of:\n>      - `Camera::addBuffer()`\n>      - `Request::enableStream()`\n>    * replace `Request::reuse(ReuseBuffers)` with a combination of:\n>      - `Camera::addBuffer()` for each buffer in the request\n>      - `Request::reuse()`\n>      - `Request::enableStream()` for each target stream\n>\n> I believe patch \"py: Use camera buffer pool\" (especially src/py/examples/simple-cam.py)\n> should showcase the minimal \"start-camera-and-request-frames\" application\n> you're looking for (albeit in python, not C++). But let me know if you need a better example.\n> In any case, if the details of the API are finalized, https://gitlab.freedesktop.org/camera/simple-cam\n> will be updated to reflect the changes.\n>\n> The only complication is that `Camera::addBuffer()` is only allowed after `Camera::start()`.\n> And there are some unsure details still, specifically related to how buffers\n> can / cannot be returned without a request (i.e. how can a pipeline handler\n> \"reject\" a buffer and how can the application recognize that).\n>\n>\n> Regards,\n> Barnabás Pőcze\n>\n> >\n> > Thanks\n> > David\n> >\n> > On Fri, 3 Jul 2026 at 15:37, Barnabás Pőcze\n> > <barnabas.pocze@ideasonboard.com> wrote:\n> >>\n> >> Hi\n> >>\n> >> I have tried to answer the questions, let me know if I'd missed anything.\n> >>\n> >> 2026. 07. 03. 14:37 keltezéssel, David Plowman írta:\n> >>> Hi Barnabas\n> >>>\n> >>> Thanks for working on all this, very excited to see progress on this topic!\n> >>>\n> >>> Unfortunately I'm about to disappear on holiday for 2 weeks, so this\n> >>> reply is going to turn into a long list of questions that I've not had\n> >>> a huge amount of time to think about, so apologies in advance for\n> >>> that.\n> >>>\n> >>> On Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n> >>> <barnabas.pocze@ideasonboard.com> wrote:\n> >>>>\n> >>>> This is the first RFC changeset for splitting requests and buffers. It largely\n> >>>> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n> >>>> already reviewed.\n> >>>>\n> >>>> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n> >>>>\n> >>>> ---\n> >>>>\n> >>>> # introduction\n> >>>>\n> >>>> The basic idea is that requests no longer have buffers when they are submitted,\n> >>>> and the camera keeps track of a set of buffers for each stream, and buffers will\n> >>>> be attached to requests from this pool in an unspecified order\n> >>>>\n> >>>> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n> >>>> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n> >>>> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n> >>>> is used to set which streams a request wants frames from.\n> >>>\n> >>> I guess I'm vaguely expecting the buffer pool mechanism to be to a\n> >>> large extent separate from the camera system. So the camera system\n> >>> will obviously be a client of it, but otherwise they're not really\n> >>> intertwined. Is that likely to be the case here? Or maybe it's not\n> >>> possible.\n> >>\n> >> The buffer pool mechanism is implemented in the \"Camera\" and related types.\n> >> And not in e.g. a separate `BufferPool` type. This was deemed the simpler\n> >> approach. But there are no technical obstacles as far as I can tell.\n> >> Or do you mean something else?\n> >>\n> >>\n> >>>\n> >>> I'm also vaguely feeling an application might want to control the\n> >>> lifetime of the pool and contents. For example, when the camera is\n> >>> stopped, maybe you want to leave your buffers in the pool so that you\n> >>> can simply restart it? Wasn't sure if that kind of behaviour is\n> >>> envisaged here.\n> >>\n> >> I don't think that option was discussed, but could be implemented.\n> >> Nonetheless then `configure()` has to clear the pool in any case,\n> >> which is technically a bit more complicated to do.\n> >>\n> >>\n> >>>\n> >>>>\n> >>>> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n> >>>> buffer for the given stream. If this buffer is not acceptable, then\n> >>>> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n> >>>> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n> >>>>\n> >>>> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n> >>>> the `PipelineHandler` base class fills each request with buffers before\n> >>>> calling `queueRequestDevice()`.\n> >>>\n> >>> One thing I raised a while back was whether there are applications\n> >>> that want to target specific buffers at particular requests. I'm\n> >>> thinking of Android here, though Android remains a giant mystery to\n> >>> me. But maybe another application might have a reason to do that?\n> >>\n> >> Android has caused quite a bit of headache, so in the end a switch\n> >> to their \"new\" buffer model was made: https://source.android.com/docs/core/camera/buffer-management-api\n> >>\n> >> This uses a similar pool based approach where requests no longer contain any buffers.\n> >>\n> >>\n> >>>\n> >>> The thought was to leave *optional* buffers in request. If it's there,\n> >>> you use it and otherwise the camera system goes to the buffer pool to\n> >>> get one. It sort of feels to me like it should be doable, but is it\n> >>> useful?\n> >>>\n> >>> I used to wonder whether an application might want to hold back a\n> >>> number of buffers so that it could do a burst capture, guaranteeing to\n> >>> have a buffer for every request. But I'm not so convinced by that,\n> >>> presumably you can check if you have enough buffers in the pool.\n> >>>\n> >>> Though having optional buffers would certainly ease migration to the new scheme!\n> >>\n> >> I don't have a satisfactory answer unfortunately. I think it's a matter\n> >> of making a decision, it seems technically feasible. Of course it would\n> >> complicate the core and pipeline handler parts.\n> >>\n> >> There is also a question of how to handle requests that mix both:\n> >> having some buffers and also some \"just\" enabled streams. Then\n> >> fences must also not be forgotten about. And then it has to be evaluated\n> >> how many technical difficulties supporting this mixed model would cause for\n> >> the existing pipeline handler implementations.\n> >>\n> >> An earlier prototype explored the idea of automatically adding buffers\n> >> from requests to the pool when they are queued. This of course would\n> >> break the association between buffers and requests, so it wouldn't\n> >> address your point. And it was decided not to go forward with this\n> >> compatibility behaviour in any case.\n> >>\n> >>\n> >>>\n> >>>>\n> >>>>\n> >>>> # discussion points\n> >>>>\n> >>>> ## adding buffers before `Camera::start()`\n> >>>>\n> >>>> Currently buffers can only be added in the \"Running\" state. They could\n> >>>> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n> >>>> and putting it into `stop()` would be a bit asymmetric.\n> >>>\n> >>> Indeed, I've always wanted to queue requests before starting the camera!\n> >>>\n> >>>>\n> >>>> ## empty pool notification\n> >>>>\n> >>>> Currently there is no mechanism for the application to know how many\n> >>>> buffers it should keep in the pool. I think a signal to notify the application\n> >>>> when it should add more buffers for a given stream could be added. But the\n> >>>> main idea was to expose some kind of minimum buffer count quantity.\n> >>>>\n> >>>> ## requirements towards application wrt. buffers\n> >>>>\n> >>>> With this prototype, an application is essentially required to always process *all*\n> >>>> buffers in *all* completed requests, otherwise it might lose buffers. (This\n> >>>> applies to cancelled requests as well.) Is that reasonable?\n> >>>\n> >>> I think it sounds OK to expect applications to manage buffers, at\n> >>> least to an extent. As I remarked above, I think maybe applications\n> >>> will want to manage buffers for their own convenience.\n> >>>\n> >>>>\n> >>>> ## returning unused buffers\n> >>>>\n> >>>> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n> >>>> where `request == nullptr`. This works, but may not be the best interface.\n> >>>>\n> >>>> ## returning rejected buffers\n> >>>>\n> >>>> Pipeline handlers can reject buffers. But how should that be signalled to the\n> >>>> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n> >>>> But this is not ideal because there isn't really a way to distinguish it from\n> >>>> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n> >>>> because `FrameError` requires some other fields to be valid.\n> >>>>\n> >>>> ## extending `completeBuffer()` with stream parameter\n> >>>>\n> >>>> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n> >>>> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n> >>>> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n> >>>> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n> >>>\n> >>> It does feel a bit strange to me that buffers should know about\n> >>> streams, and so on. I think I was expecting buffers/pools to be\n> >>> largely independent of such things. But I accept there might be a good\n> >>> reason.\n> >>\n> >> Indeed they shouldn't. But migrating straight to `completeBuffer(req, stream, buf)`\n> >> world where buffers have no idea about requests and streams\n> >> is not as simple as I would have liked. Especially since most\n> >> pipeline handlers are written with the current model in mind\n> >> where a buffer is already in a request associated with a stream.\n> >> And so the actual stream is not even easily available at buffer\n> >> completion time in many cases. So this is a compromise.\n> >>\n> >>\n> >>>\n> >>>>\n> >>>> ## fence timeout\n> >>>>\n> >>>> Previously a hard-coded timeout was used for fences. This is now removed.\n> >>>> Should there be a hard-coded fixed timeout for fences?\n> >>>>\n> >>>>\n> >>>> # TODO\n> >>>>\n> >>>> # converting more pipeline handlers\n> >>>>\n> >>>> Only the uvcvideo pipeline handler is converted to use the buffer pool\n> >>>> directly as an experiment, but more should be converted to really see\n> >>>> if this public api is a good fit for pipeline handlers. Especially something\n> >>>> like `imx8-isi` since that has a bit different architecture from the others.\n> >>>>\n> >>>> # minimum buffer count\n> >>>>\n> >>>> The applications need to know how many buffers should be kept in the pool\n> >>>> for a given stream for continuous streaming. This should be a property or\n> >>>> similar.\n> >>>\n> >>> Yes, I guess so. In practice we always allocate way more than the\n> >>> minimum, simply because that avoids frame drops.\n> >>\n> >> Yes, but this information can be useful if the buffer goes into a processing pipeline\n> >> that holds on to it, or if the applications creates its own `FrameBuffer`s without\n> >> the `FrameBufferAllocator`.\n> >>\n> >>\n> >>>\n> >>>>\n> >>>> # `FrameBuffer::Private::request()`\n> >>>>\n> >>>> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n> >>>> should probably be removed to fully decouple the two.\n> >>>\n> >>> One other slightly unusual use case I'd like to add into the mix is\n> >>> one I remember hearing on a Kamaros call. There's a stream of frames\n> >>> coming back from a camera, but then there's a second stream, made from\n> >>> the same sensor images, but which is generated only occasionally (so\n> >>> runs at a lower framerate).\n> >>>\n> >>> Does the buffer pool mechanism give us a way to handle this? When a\n> >>> request completes there could be 3 outcomes - 1. here's your buffer,\n> >>> 2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\n> >>> actually a frame generated for this stream on this occasion.\n> >>\n> >> You mean like a stream that might not supply a frame even if the\n> >> request enables it, there are available buffers, and no errors\n> >> are encountered? Or put differently, a stream that \"itself\" decides\n> >> when to supply frames regardless of the streams in the request?\n> >>\n> >> In that case currently (2) and (3) cannot be differentiated. But\n> >> it's a matter of extending the buffer map in the request.\n> >>\n> >>\n> >>>\n> >>> The final thing I'd like to discuss is how this relates to control\n> >>> queues. Of course, strictly speaking the two subjects are independent,\n> >>> but nonetheless I have a couple of questions.\n> >>>\n> >>> * The buffer/request split will obviously break the existing API and\n> >>> cause a certain amount of work. If we're going to have control queues,\n> >>> are we going to break everything again later, or do it all at once?\n> >>> Just wondering...\n> >>\n> >> I suppose it would be better to break the world once, but I'm no\n> >> authority on the question of libcamera stability and releases.\n> >>\n> >>\n> >>>\n> >>> * If you took control lists out of requests you might find there's\n> >>> almost nothing left in them. Wanted to check we're OK with that just\n> >>> in case we were to end up there!\n> >>\n> >> I think it's fine. A request would still have a \"cookie\" and the set\n> >> of enabled streams. And it has a sequence number, status, a set of\n> >> buffers, and a set of metadata items when it completes.\n> >>\n> >> Nonetheless we could explore getting rid of the application facing\n> >> `Request` type and using something different, maybe something more\n> >> centered around using the numeric sequence number as the identity.\n> >>\n> >>\n> >>>\n> >>> Anyway, apologies for the big dump of questions and then running away.\n> >>> Look forward to hearing more on the subject!\n> >>>\n> >>> Thanks\n> >>> David\n> >>>\n> >>>>\n> >>>> ---\n> >>>>\n> >>>> Barnabás Pőcze (54):\n> >>>>     apps: cam: Simplify buffer reuse\n> >>>>     libcamera: request: Disassociate buffer when cancelling\n> >>>>     libcamera: pipeline: Replace open-coded request cancellation\n> >>>>     libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n> >>>>     libcamera: pipeline: virtual: Make copy of request's buffer map\n> >>>>     libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n> >>>>     libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n> >>>>     v4l2: v4l2_camera: Avoid a level of indirection\n> >>>>     v4l2: v4l2_camera: Remove repated index checks\n> >>>>     v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n> >>>>     v4l2: v4l2_camera: Use actually allocated buffer count\n> >>>>     v4l2: v4l2_camera: Use buffer cookie for indexing\n> >>>>     v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n> >>>>     v4l2: v4l2_camera: Always clear pending requests\n> >>>>     v4l2: v4l2_camera: Clear completed requests when stopping\n> >>>>     v4l2: v4l2_camera: Provide buffers one by one\n> >>>>     test: fence: Disable temporarily\n> >>>>     libcamera: request: Remove `ReuseBuffers`\n> >>>>     libcamera: framebuffer: request(): Move to private type\n> >>>>     libcamera: framebuffer: Store associated Stream\n> >>>>     libcamera: camera: Add `StreamData`\n> >>>>     libcamera: camera: Add buffer pool\n> >>>>     libcamera: request: addBuffer(): Remove impl\n> >>>>     libcamera: request: Remove fence support\n> >>>>     libcamera: request: Store count of pending buffers\n> >>>>     libcamera: request: doCancelRequest(): Remove\n> >>>>     libcamera: pipeline_handler: Move constructor options to a separate\n> >>>>       type\n> >>>>     libcamera: pipeline_handler: Acquire buffers if not using pool\n> >>>>     libcamera: request: enableStream(): Add\n> >>>>     libcamera: camera: acquireBuffer(): Add\n> >>>>     libcamera: camera: rejectBuffer(): Add\n> >>>>     libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n> >>>>       function\n> >>>>     libcamera: pipeline_handler: Use `std::deque`\n> >>>>     libcamera: pipeline_handler: completeRequest(): Return request count\n> >>>>     libcamera: pipeline: uvcvideo: Use buffer pool prototype\n> >>>>     libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n> >>>>     libcamera: camera: bufferCompleted: Pass `Stream` as well\n> >>>>     libcamera: camera: queueRequest(): Adjust buffer map empty error\n> >>>>       message\n> >>>>     libcamera: camera: queueBuffer(): Reject if it has buffers\n> >>>>     apps: cam: Use camera buffer pool\n> >>>>     app: lc-compliance: Use camera buffer pool\n> >>>>     apps: lc-compliance: Add buffer pool tests\n> >>>>     test: Use camera buffer pool\n> >>>>     apps: qcam: Use camera buffer pool\n> >>>>     v4l2: Use camera buffer pool\n> >>>>     py: Use camera buffer pool\n> >>>>     gstreamer: Use camera buffer pool\n> >>>>     libcamera: request: Remove `ReuseFlag`\n> >>>>     android: Update imported files\n> >>>>     android: camera_request: Add helper for buffer conversion\n> >>>>     android: camera_device: Move fence restoration into\n> >>>>       `prepareToReturn()`\n> >>>>     android: Use camera buffer pool\n> >>>>     libcamera: request: Remove `addBuffer()`\n> >>>>     test: fence: Enable\n> >>>>\n> >>>>    .../guides/application-developer.rst          |    9 -\n> >>>>    Documentation/guides/pipeline-handler.rst     |   10 +-\n> >>>>    .../libhardware/include/hardware/camera3.h    |  360 +-\n> >>>>    .../include/hardware/camera_common.h          |  304 +-\n> >>>>    .../libhardware/include/hardware/gralloc.h    |   99 +-\n> >>>>    .../android/metadata/camera_metadata_hidden.h |   11 +-\n> >>>>    .../android/metadata/system/camera_metadata.h |   41 +-\n> >>>>    .../metadata/system/camera_metadata_tags.h    |  633 +-\n> >>>>    .../metadata/system/camera_vendor_tags.h      |   10 +-\n> >>>>    .../android/system/core/include/android/log.h |  450 +-\n> >>>>    .../core/include/cutils/native_handle.h       |   62 +-\n> >>>>    .../system/core/include/system/camera.h       |    4 +-\n> >>>>    .../core/include/system/graphics-base-v1.2.h  |   36 +\n> >>>>    .../core/include/system/graphics-base.h       |    1 +\n> >>>>    .../system/core/include/system/graphics.h     |   10 +-\n> >>>>    include/libcamera/camera.h                    |    5 +-\n> >>>>    include/libcamera/framebuffer.h               |    1 -\n> >>>>    include/libcamera/internal/camera.h           |   46 +-\n> >>>>    include/libcamera/internal/framebuffer.h      |    6 +\n> >>>>    include/libcamera/internal/pipeline_handler.h |   31 +-\n> >>>>    include/libcamera/internal/request.h          |   24 +-\n> >>>>    include/libcamera/request.h                   |   10 +-\n> >>>>    src/android/camera3_hal.cpp                   |    3 +\n> >>>>    src/android/camera_capabilities.cpp           |    3 +\n> >>>>    src/android/camera_device.cpp                 |  287 +-\n> >>>>    src/android/camera_device.h                   |    4 +\n> >>>>    src/android/camera_hal_manager.cpp            |    2 +-\n> >>>>    src/android/camera_ops.cpp                    |   16 +-\n> >>>>    src/android/camera_request.cpp                |   53 +-\n> >>>>    src/android/camera_request.h                  |   11 +-\n> >>>>    src/android/metadata/camera_metadata.c        |  183 +-\n> >>>>    .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n> >>>>    src/apps/cam/camera_session.cpp               |   36 +-\n> >>>>    src/apps/cam/camera_session.h                 |    2 +-\n> >>>>    src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n> >>>>    src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n> >>>>    src/apps/qcam/main_window.cpp                 |   82 +-\n> >>>>    src/apps/qcam/main_window.h                   |    1 -\n> >>>>    src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n> >>>>    src/libcamera/camera.cpp                      |  164 +-\n> >>>>    src/libcamera/fence.cpp                       |   15 +-\n> >>>>    src/libcamera/framebuffer.cpp                 |   57 +-\n> >>>>    src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n> >>>>    src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n> >>>>    src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n> >>>>    src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n> >>>>    src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n> >>>>    src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n> >>>>    .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n> >>>>    .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n> >>>>    src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n> >>>>    src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n> >>>>    src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n> >>>>    src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n> >>>>    src/libcamera/pipeline_handler.cpp            |  260 +-\n> >>>>    src/libcamera/request.cpp                     |  290 +-\n> >>>>    src/py/cam/cam.py                             |   20 +-\n> >>>>    src/py/examples/simple-cam.py                 |   13 +-\n> >>>>    src/py/examples/simple-capture.py             |   20 +-\n> >>>>    src/py/examples/simple-continuous-capture.py  |   32 +-\n> >>>>    src/py/libcamera/py_main.cpp                  |   65 +-\n> >>>>    src/v4l2/v4l2_camera.cpp                      |  150 +-\n> >>>>    src/v4l2/v4l2_camera.h                        |   25 +-\n> >>>>    src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n> >>>>    src/v4l2/v4l2_camera_proxy.h                  |    3 -\n> >>>>    test/camera/buffer_import.cpp                 |   22 +-\n> >>>>    test/camera/camera_reconfigure.cpp            |   22 +-\n> >>>>    test/camera/capture.cpp                       |   24 +-\n> >>>>    test/camera/statemachine.cpp                  |    4 +-\n> >>>>    test/fence.cpp                                |  214 +-\n> >>>>    70 files changed, 9182 insertions(+), 1283 deletions(-)\n> >>>>    create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n> >>>>\n> >>>> --\n> >>>> 2.54.0\n> >>\n>","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 D40D4BDE4C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Jul 2026 12:03:02 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 82B5767F06;\n\tFri, 24 Jul 2026 14:03:02 +0200 (CEST)","from mail-ed1-x533.google.com (mail-ed1-x533.google.com\n\t[IPv6:2a00:1450:4864:20::533])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B040567EE1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jul 2026 14:03:00 +0200 (CEST)","by mail-ed1-x533.google.com with SMTP id\n\t4fb4d7f45d1cf-69c108fee7fso441752a12.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jul 2026 05:03:00 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"jWWyX6v3\"; dkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1784894580; cv=none;\n\td=google.com; s=arc-20260327;\n\tb=RhR++P9tTXm2ZrBO9fNvXJNzJ/FddIjy2HoeGxxBwbARUxsFdy4PwseZW0xrAxR0Eh\n\tMXj9qLnvJMEIA0RnfEN+6dnDlmlQhxpBo/MMUj1CWdyrr2thaSDWORjpbvDKImxmxg87\n\tP/JVkk4txzwsm7W7+iTulG8zS7HydH/vvCpsqgRJ5fePi0eOzz6wBhP50FUih+2jTDvk\n\tzgcDKfWYMEeKlkeF43rDwR1d2LfeOMrEPDcjsrjlWCFjWlfRZVkcrRbmJxkBrizj+3VO\n\tagm6JA7ngoXhsRb43veFrFpuuH2BSywEZAHK++pZjq2ftI3y3EcxW+y/q/fosKPcKlkw\n\tZkhw==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n\ts=arc-20260327; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:dkim-signature;\n\tbh=FMkJbUMAiNo5i4nGSdLlUYnPZ0UT5TYojtMUWWcZhKY=;\n\tfh=6eMZ9Peh5oKJMXVlU5do7GxLXGl0cSCd64pkjvWpyo4=;\n\tb=K54u7vh2oaVxK62OgS2qw5AuFPtTtrr7yrBo4bxXFdoUysCABbEALzKy5yQ2tBL46Z\n\t3cppR3HIz1CP692K3EcA/jqBvPKiS7aHAG+r3cp1I580K4D39kq2tbxcRtmHsdISsRv5\n\tElAbW9GteyW4S8weWnGN+D0gyA5EI7AAlYYhM5iDwuz12abWtqSj8b+KFRc6H7i0Gvfe\n\tX8NYKgGeZ2+jnIN9YSPKfYKMpGbhjSmuMDfXg2c3KvxPhSXaeg+tyJ1jlYn6jRFFlhIM\n\teQDuH1Fwohkn7mzIEyPT1QZFIaps9PHh/ZS7gmLwc+FCtOur9nDZtZYNnGxeNU0dSYGE\n\tAf4g==; darn=lists.libcamera.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1784894580; x=1785499380;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:from:to:cc:subject\n\t:date:message-id:reply-to:content-type;\n\tbh=FMkJbUMAiNo5i4nGSdLlUYnPZ0UT5TYojtMUWWcZhKY=;\n\tb=jWWyX6v3QmUHg//8PhdyJQbg/5LTi0NO9GcyqRLVExJLD0+Y8h/laazQ5H7DjiKoVR\n\t+14rhEYRPScgOLJCmgrR0gOJJkwWW/bx/T9zGV6i9QfwXLzJLLVKbSp1w1V29uIW5/JI\n\twd9b6L87sqV5tAQHY9a7B37G5Ix/j6/caeIn8EMT1UFPbsqUQbWnUddNs41PkFHuNFVH\n\tTQNEdjmaq9VYRyYhyCT6BF9Qkqs9UdyD+8+iZ1453yLcxQqYxpInCq/YdQi2821uPfF3\n\t9gmdBlqAfwiUpgx4k4bE9yzqtichshnGbztnZcTatBsXM10eQD/Ppozy+1D40gfKtoox\n\tF1Kg==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784894580; x=1785499380;\n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to\n\t:content-type;\n\tbh=FMkJbUMAiNo5i4nGSdLlUYnPZ0UT5TYojtMUWWcZhKY=;\n\tb=cCJbvul3oK6eOFr+LkhF8Q8rvqn0ohNjE/SkijPoABm4pJ7hzEe3Zy2ZyfzSP1bLi0\n\tJIFmAln8rJNEdrfOJLnNixEAL3abBUs7ryfdKYIP7mBhjLOGu/PhA0KfBiqJZvnj8T0w\n\tN08JGmPt0gvOz8hCWKKFnXHn+uEYcZGRcnDPVHmFfM5GGTLVsXHE9Z71qTob4AA67Poq\n\t9ygO/1yDNjIcWuoGr/221QFsf6SYqj46T/U952hEu8z/e4C1JcMQSM0hfHkUNGcJdHb+\n\t87x4MQhE8YslsuVaUSkNtxtEhV2vs6NlIr8CYZHgYR9ftXXjJIOgONMRA7B6sUeNtcrT\n\tjfkw==","X-Gm-Message-State":"AOJu0YyglLJA0iVFXB7qC70/LBozVzy+jdDmzc7a9IGvNyJe4cr92K9D\n\tCEDGXVdA2/VlQPioXauX930bYTvGbzSbK0D7P7Yb+BHMYJtUAXq0cofY9reDa8QLXPFTn5BQsPf\n\tcsQSHKLPF1XJDeHIaiqzz2NFG1FSdScGGun16mszSM+tM4a8RmdklQ1s=","X-Gm-Gg":"AR+sD11BoFBNPk9PP1M0lkzaUlIjUUDT27BA1HloLY8HOVEgzofwVrSHOLZ/7y0FgN4\n\tzPta/8JK/RQdtXVtFqn+IgwTZgE/uuMvLb2rU228bCryb3eBH7PxurZYmSqmXwPEvN6fiV1BPKo\n\th3H0skcsHRMsauwnrVdoKosv3TdSFr6AxNpBrjFE3/Z1cwl+TnJJhCMQAwye07vQpGykitBNwEH\n\tkS6n+fJSzcohtg9rR3wI2CskbGDU5Rhc5m3H4hyg3201JdLKSkq5v+8ni6g2xi2PNvIWOHD+ZnY\n\tYboLh1tBQvVugWQw10cow8JWBzUog/ZAM85aP6cHzZABhYG8d0+iqhxHbjXN85F2VqVSSWFTFH4\n\tjXw==","X-Received":"by 2002:a05:6402:c44:b0:69e:648e:2582 with SMTP id\n\t4fb4d7f45d1cf-69f6c5eff58mr3022460a12.20.1784894579832;\n\tFri, 24 Jul 2026 05:02:59 -0700 (PDT)","MIME-Version":"1.0","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>\n\t<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>\n\t<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>\n\t<6tLdsPxodLNz3BDMEKU1_ZOQefpKwKapmLdAYPy8mlyZoh2gLSJF0_niM_9SMUK1C-zBMyPOFhMvo0PWN_ib7A==@protonmail.internalid>\n\t<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>\n\t<52279d34-59ec-4e62-b82b-04a40b784b41@ideasonboard.com>","In-Reply-To":"<52279d34-59ec-4e62-b82b-04a40b784b41@ideasonboard.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Fri, 24 Jul 2026 13:02:48 +0100","X-Gm-Features":"AUfX_mw_pICz4oBm6N2-xH0cyqcRiUqeYh2WT38JBM8eZNcsM7cVwz6fGgHluxc","Message-ID":"<CAHW6GYJna1S=1cP96O+MSUTCOhvYi_VRA62+xXUXr_JvhVZzJw@mail.gmail.com>","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39829,"web_url":"https://patchwork.libcamera.org/comment/39829/","msgid":"<c7dd2055-f6cf-4a84-bf51-2fb59d9f2350@ideasonboard.com>","date":"2026-07-24T12:55:58","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"2026. 07. 24. 14:02 keltezéssel, David Plowman írta:\n> Hi again\n> \n> Sorry for asking another question!\n> \n> On Thu, 23 Jul 2026 at 16:42, Barnabás Pőcze\n> <barnabas.pocze@ideasonboard.com> wrote:\n>>\n>> Hi\n>>\n>> 2026. 07. 23. 13:03 keltezéssel, David Plowman írta:\n>>> Hi Barnabas\n>>>\n>>> Thanks for your replies.\n>>>\n>>> I think mostly I'm happy enough with things, though I wasn't quite\n>>> clear why configure() has to empty the buffer pools (and you can't\n>>> simply leave stuff in them), I obviously haven't quite understood\n>>> something there.\n>>\n>> The thinking is that configuration most likely changes the size of the\n>> resulting images, so leaving buffers that were created with the previous\n>> configuration in mind could be problematic. It's simpler to just always\n>> ensure that the pool is empty after configuration.\n>>\n>>\n>>>\n>>> The Android doc that you linked to was interesting, and is definitely\n>>> an improvement. I've been complaining about this \"targeting specific\n>>> buffers\" thing for years! It feels like libcamera will end up more\n>>> like Android once all this has been done. I note that Android appears\n>>> to make no allowance for the\n>>> controls-stuck-at-the-back-of-the-request-queue problem, so I'd be\n>>> interested to hear what folks think about that.\n>>>\n>>> Finally, is there any chance of getting any more visibility of the new\n>>> API? In particular, seeing a minimal \"start-camera-and-request-frames\"\n>>> application might make it all feel a bit more concrete!\n>>\n>> Most things remain the same, the main conceptual difference is that\n>> `Camera::addBuffer()` needs to be called to provide the buffers,\n>> and the targeted streams must be explicitly enabled in a request\n>> with `Request::enableStream()`\n> \n> Something was bothering me a bit here, and it finally dawned on me what it was.\n> \n> In the Android world, where control lists are synchronised with the\n> request you put them in, this seems fine.\n> \n> However, if you want to be able to send control lists that bypass the\n> request queue, then you have no way to synchronise the enabling of a\n> buffer with that control list.\n> \n> So the most obvious example is if I'm running with, say, 16 requests\n> circulating, because I have a Pi that's busy or slow and I don't want\n> to drop frames. Now I want to do a capture with exposure X and enable\n> a buffer for my high resolution stream for that capture (for which I\n> am not normally enabling buffers). I have no way to send my control\n> \"early\" and enable a buffer for it. (Instead, the whole system would\n> be forced to work in \"Android mode\", and you'd have to submit a\n> request and wait 16 frames for your buffer to arrive. Ouch!)\n\nThat's true, but unless I'm missing something, this would be a limitation if one\njust added control queues even with the current model (request has buffers), no?\n\nAnd just so I don't misunderstand, the requirement is to be able to fast-track controls\nin a way that enables the application to also capture arbitrary streams from the (first)\nframe on which the fast-tracked controls were in effect?\n\n> \n> The obvious answer would seem to be that enabling buffers should be a\n> control. In the Android world that would work just the same, because\n> they're synchronised, but it would also enable the use case above\n> that's important to us. Or one could let applications do it either\n> way, I suppose.\n> \n> Any thoughts?\n\nGiven that a `Request` is a collection of controls and enabled streams, wouldn't it\nmake sense to have a way to fast-track a request?\n\nIf there is a separate `ControlList` queue and streams are passed as a control, it's\nnot clear to me how one could select the request to complete with the buffers and how\none would reconcile potential conflicts wrt. the enabled streams and controls in that\nrequest. I suppose maybe the enabled streams lists could just be merged.\n\nOr am I misunderstanding something?\n\n\n> \n> Thanks!\n> David\n> \n>>\n>> The most straightforward way to convert an application would be something like this:\n>>     * replace `Request::addBuffer()` with a combination of:\n>>       - `Camera::addBuffer()`\n>>       - `Request::enableStream()`\n>>     * replace `Request::reuse(ReuseBuffers)` with a combination of:\n>>       - `Camera::addBuffer()` for each buffer in the request\n>>       - `Request::reuse()`\n>>       - `Request::enableStream()` for each target stream\n>>\n>> I believe patch \"py: Use camera buffer pool\" (especially src/py/examples/simple-cam.py)\n>> should showcase the minimal \"start-camera-and-request-frames\" application\n>> you're looking for (albeit in python, not C++). But let me know if you need a better example.\n>> In any case, if the details of the API are finalized, https://gitlab.freedesktop.org/camera/simple-cam\n>> will be updated to reflect the changes.\n>>\n>> The only complication is that `Camera::addBuffer()` is only allowed after `Camera::start()`.\n>> And there are some unsure details still, specifically related to how buffers\n>> can / cannot be returned without a request (i.e. how can a pipeline handler\n>> \"reject\" a buffer and how can the application recognize that).\n>>\n>>\n>> Regards,\n>> Barnabás Pőcze\n>>\n>>>\n>>> Thanks\n>>> David\n>>>\n>>> On Fri, 3 Jul 2026 at 15:37, Barnabás Pőcze\n>>> <barnabas.pocze@ideasonboard.com> wrote:\n>>>>\n>>>> Hi\n>>>>\n>>>> I have tried to answer the questions, let me know if I'd missed anything.\n>>>>\n>>>> 2026. 07. 03. 14:37 keltezéssel, David Plowman írta:\n>>>>> Hi Barnabas\n>>>>>\n>>>>> Thanks for working on all this, very excited to see progress on this topic!\n>>>>>\n>>>>> Unfortunately I'm about to disappear on holiday for 2 weeks, so this\n>>>>> reply is going to turn into a long list of questions that I've not had\n>>>>> a huge amount of time to think about, so apologies in advance for\n>>>>> that.\n>>>>>\n>>>>> On Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n>>>>> <barnabas.pocze@ideasonboard.com> wrote:\n>>>>>>\n>>>>>> This is the first RFC changeset for splitting requests and buffers. It largely\n>>>>>> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n>>>>>> already reviewed.\n>>>>>>\n>>>>>> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n>>>>>>\n>>>>>> ---\n>>>>>>\n>>>>>> # introduction\n>>>>>>\n>>>>>> The basic idea is that requests no longer have buffers when they are submitted,\n>>>>>> and the camera keeps track of a set of buffers for each stream, and buffers will\n>>>>>> be attached to requests from this pool in an unspecified order\n>>>>>>\n>>>>>> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n>>>>>> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n>>>>>> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n>>>>>> is used to set which streams a request wants frames from.\n>>>>>\n>>>>> I guess I'm vaguely expecting the buffer pool mechanism to be to a\n>>>>> large extent separate from the camera system. So the camera system\n>>>>> will obviously be a client of it, but otherwise they're not really\n>>>>> intertwined. Is that likely to be the case here? Or maybe it's not\n>>>>> possible.\n>>>>\n>>>> The buffer pool mechanism is implemented in the \"Camera\" and related types.\n>>>> And not in e.g. a separate `BufferPool` type. This was deemed the simpler\n>>>> approach. But there are no technical obstacles as far as I can tell.\n>>>> Or do you mean something else?\n>>>>\n>>>>\n>>>>>\n>>>>> I'm also vaguely feeling an application might want to control the\n>>>>> lifetime of the pool and contents. For example, when the camera is\n>>>>> stopped, maybe you want to leave your buffers in the pool so that you\n>>>>> can simply restart it? Wasn't sure if that kind of behaviour is\n>>>>> envisaged here.\n>>>>\n>>>> I don't think that option was discussed, but could be implemented.\n>>>> Nonetheless then `configure()` has to clear the pool in any case,\n>>>> which is technically a bit more complicated to do.\n>>>>\n>>>>\n>>>>>\n>>>>>>\n>>>>>> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n>>>>>> buffer for the given stream. If this buffer is not acceptable, then\n>>>>>> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n>>>>>> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n>>>>>>\n>>>>>> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n>>>>>> the `PipelineHandler` base class fills each request with buffers before\n>>>>>> calling `queueRequestDevice()`.\n>>>>>\n>>>>> One thing I raised a while back was whether there are applications\n>>>>> that want to target specific buffers at particular requests. I'm\n>>>>> thinking of Android here, though Android remains a giant mystery to\n>>>>> me. But maybe another application might have a reason to do that?\n>>>>\n>>>> Android has caused quite a bit of headache, so in the end a switch\n>>>> to their \"new\" buffer model was made: https://source.android.com/docs/core/camera/buffer-management-api\n>>>>\n>>>> This uses a similar pool based approach where requests no longer contain any buffers.\n>>>>\n>>>>\n>>>>>\n>>>>> The thought was to leave *optional* buffers in request. If it's there,\n>>>>> you use it and otherwise the camera system goes to the buffer pool to\n>>>>> get one. It sort of feels to me like it should be doable, but is it\n>>>>> useful?\n>>>>>\n>>>>> I used to wonder whether an application might want to hold back a\n>>>>> number of buffers so that it could do a burst capture, guaranteeing to\n>>>>> have a buffer for every request. But I'm not so convinced by that,\n>>>>> presumably you can check if you have enough buffers in the pool.\n>>>>>\n>>>>> Though having optional buffers would certainly ease migration to the new scheme!\n>>>>\n>>>> I don't have a satisfactory answer unfortunately. I think it's a matter\n>>>> of making a decision, it seems technically feasible. Of course it would\n>>>> complicate the core and pipeline handler parts.\n>>>>\n>>>> There is also a question of how to handle requests that mix both:\n>>>> having some buffers and also some \"just\" enabled streams. Then\n>>>> fences must also not be forgotten about. And then it has to be evaluated\n>>>> how many technical difficulties supporting this mixed model would cause for\n>>>> the existing pipeline handler implementations.\n>>>>\n>>>> An earlier prototype explored the idea of automatically adding buffers\n>>>> from requests to the pool when they are queued. This of course would\n>>>> break the association between buffers and requests, so it wouldn't\n>>>> address your point. And it was decided not to go forward with this\n>>>> compatibility behaviour in any case.\n>>>>\n>>>>\n>>>>>\n>>>>>>\n>>>>>>\n>>>>>> # discussion points\n>>>>>>\n>>>>>> ## adding buffers before `Camera::start()`\n>>>>>>\n>>>>>> Currently buffers can only be added in the \"Running\" state. They could\n>>>>>> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n>>>>>> and putting it into `stop()` would be a bit asymmetric.\n>>>>>\n>>>>> Indeed, I've always wanted to queue requests before starting the camera!\n>>>>>\n>>>>>>\n>>>>>> ## empty pool notification\n>>>>>>\n>>>>>> Currently there is no mechanism for the application to know how many\n>>>>>> buffers it should keep in the pool. I think a signal to notify the application\n>>>>>> when it should add more buffers for a given stream could be added. But the\n>>>>>> main idea was to expose some kind of minimum buffer count quantity.\n>>>>>>\n>>>>>> ## requirements towards application wrt. buffers\n>>>>>>\n>>>>>> With this prototype, an application is essentially required to always process *all*\n>>>>>> buffers in *all* completed requests, otherwise it might lose buffers. (This\n>>>>>> applies to cancelled requests as well.) Is that reasonable?\n>>>>>\n>>>>> I think it sounds OK to expect applications to manage buffers, at\n>>>>> least to an extent. As I remarked above, I think maybe applications\n>>>>> will want to manage buffers for their own convenience.\n>>>>>\n>>>>>>\n>>>>>> ## returning unused buffers\n>>>>>>\n>>>>>> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n>>>>>> where `request == nullptr`. This works, but may not be the best interface.\n>>>>>>\n>>>>>> ## returning rejected buffers\n>>>>>>\n>>>>>> Pipeline handlers can reject buffers. But how should that be signalled to the\n>>>>>> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n>>>>>> But this is not ideal because there isn't really a way to distinguish it from\n>>>>>> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n>>>>>> because `FrameError` requires some other fields to be valid.\n>>>>>>\n>>>>>> ## extending `completeBuffer()` with stream parameter\n>>>>>>\n>>>>>> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n>>>>>> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n>>>>>> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n>>>>>> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n>>>>>\n>>>>> It does feel a bit strange to me that buffers should know about\n>>>>> streams, and so on. I think I was expecting buffers/pools to be\n>>>>> largely independent of such things. But I accept there might be a good\n>>>>> reason.\n>>>>\n>>>> Indeed they shouldn't. But migrating straight to `completeBuffer(req, stream, buf)`\n>>>> world where buffers have no idea about requests and streams\n>>>> is not as simple as I would have liked. Especially since most\n>>>> pipeline handlers are written with the current model in mind\n>>>> where a buffer is already in a request associated with a stream.\n>>>> And so the actual stream is not even easily available at buffer\n>>>> completion time in many cases. So this is a compromise.\n>>>>\n>>>>\n>>>>>\n>>>>>>\n>>>>>> ## fence timeout\n>>>>>>\n>>>>>> Previously a hard-coded timeout was used for fences. This is now removed.\n>>>>>> Should there be a hard-coded fixed timeout for fences?\n>>>>>>\n>>>>>>\n>>>>>> # TODO\n>>>>>>\n>>>>>> # converting more pipeline handlers\n>>>>>>\n>>>>>> Only the uvcvideo pipeline handler is converted to use the buffer pool\n>>>>>> directly as an experiment, but more should be converted to really see\n>>>>>> if this public api is a good fit for pipeline handlers. Especially something\n>>>>>> like `imx8-isi` since that has a bit different architecture from the others.\n>>>>>>\n>>>>>> # minimum buffer count\n>>>>>>\n>>>>>> The applications need to know how many buffers should be kept in the pool\n>>>>>> for a given stream for continuous streaming. This should be a property or\n>>>>>> similar.\n>>>>>\n>>>>> Yes, I guess so. In practice we always allocate way more than the\n>>>>> minimum, simply because that avoids frame drops.\n>>>>\n>>>> Yes, but this information can be useful if the buffer goes into a processing pipeline\n>>>> that holds on to it, or if the applications creates its own `FrameBuffer`s without\n>>>> the `FrameBufferAllocator`.\n>>>>\n>>>>\n>>>>>\n>>>>>>\n>>>>>> # `FrameBuffer::Private::request()`\n>>>>>>\n>>>>>> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n>>>>>> should probably be removed to fully decouple the two.\n>>>>>\n>>>>> One other slightly unusual use case I'd like to add into the mix is\n>>>>> one I remember hearing on a Kamaros call. There's a stream of frames\n>>>>> coming back from a camera, but then there's a second stream, made from\n>>>>> the same sensor images, but which is generated only occasionally (so\n>>>>> runs at a lower framerate).\n>>>>>\n>>>>> Does the buffer pool mechanism give us a way to handle this? When a\n>>>>> request completes there could be 3 outcomes - 1. here's your buffer,\n>>>>> 2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\n>>>>> actually a frame generated for this stream on this occasion.\n>>>>\n>>>> You mean like a stream that might not supply a frame even if the\n>>>> request enables it, there are available buffers, and no errors\n>>>> are encountered? Or put differently, a stream that \"itself\" decides\n>>>> when to supply frames regardless of the streams in the request?\n>>>>\n>>>> In that case currently (2) and (3) cannot be differentiated. But\n>>>> it's a matter of extending the buffer map in the request.\n>>>>\n>>>>\n>>>>>\n>>>>> The final thing I'd like to discuss is how this relates to control\n>>>>> queues. Of course, strictly speaking the two subjects are independent,\n>>>>> but nonetheless I have a couple of questions.\n>>>>>\n>>>>> * The buffer/request split will obviously break the existing API and\n>>>>> cause a certain amount of work. If we're going to have control queues,\n>>>>> are we going to break everything again later, or do it all at once?\n>>>>> Just wondering...\n>>>>\n>>>> I suppose it would be better to break the world once, but I'm no\n>>>> authority on the question of libcamera stability and releases.\n>>>>\n>>>>\n>>>>>\n>>>>> * If you took control lists out of requests you might find there's\n>>>>> almost nothing left in them. Wanted to check we're OK with that just\n>>>>> in case we were to end up there!\n>>>>\n>>>> I think it's fine. A request would still have a \"cookie\" and the set\n>>>> of enabled streams. And it has a sequence number, status, a set of\n>>>> buffers, and a set of metadata items when it completes.\n>>>>\n>>>> Nonetheless we could explore getting rid of the application facing\n>>>> `Request` type and using something different, maybe something more\n>>>> centered around using the numeric sequence number as the identity.\n>>>>\n>>>>\n>>>>>\n>>>>> Anyway, apologies for the big dump of questions and then running away.\n>>>>> Look forward to hearing more on the subject!\n>>>>>\n>>>>> Thanks\n>>>>> David\n>>>>>\n>>>>>>\n>>>>>> ---\n>>>>>>\n>>>>>> Barnabás Pőcze (54):\n>>>>>>      apps: cam: Simplify buffer reuse\n>>>>>>      libcamera: request: Disassociate buffer when cancelling\n>>>>>>      libcamera: pipeline: Replace open-coded request cancellation\n>>>>>>      libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n>>>>>>      libcamera: pipeline: virtual: Make copy of request's buffer map\n>>>>>>      libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n>>>>>>      libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n>>>>>>      v4l2: v4l2_camera: Avoid a level of indirection\n>>>>>>      v4l2: v4l2_camera: Remove repated index checks\n>>>>>>      v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n>>>>>>      v4l2: v4l2_camera: Use actually allocated buffer count\n>>>>>>      v4l2: v4l2_camera: Use buffer cookie for indexing\n>>>>>>      v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n>>>>>>      v4l2: v4l2_camera: Always clear pending requests\n>>>>>>      v4l2: v4l2_camera: Clear completed requests when stopping\n>>>>>>      v4l2: v4l2_camera: Provide buffers one by one\n>>>>>>      test: fence: Disable temporarily\n>>>>>>      libcamera: request: Remove `ReuseBuffers`\n>>>>>>      libcamera: framebuffer: request(): Move to private type\n>>>>>>      libcamera: framebuffer: Store associated Stream\n>>>>>>      libcamera: camera: Add `StreamData`\n>>>>>>      libcamera: camera: Add buffer pool\n>>>>>>      libcamera: request: addBuffer(): Remove impl\n>>>>>>      libcamera: request: Remove fence support\n>>>>>>      libcamera: request: Store count of pending buffers\n>>>>>>      libcamera: request: doCancelRequest(): Remove\n>>>>>>      libcamera: pipeline_handler: Move constructor options to a separate\n>>>>>>        type\n>>>>>>      libcamera: pipeline_handler: Acquire buffers if not using pool\n>>>>>>      libcamera: request: enableStream(): Add\n>>>>>>      libcamera: camera: acquireBuffer(): Add\n>>>>>>      libcamera: camera: rejectBuffer(): Add\n>>>>>>      libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n>>>>>>        function\n>>>>>>      libcamera: pipeline_handler: Use `std::deque`\n>>>>>>      libcamera: pipeline_handler: completeRequest(): Return request count\n>>>>>>      libcamera: pipeline: uvcvideo: Use buffer pool prototype\n>>>>>>      libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n>>>>>>      libcamera: camera: bufferCompleted: Pass `Stream` as well\n>>>>>>      libcamera: camera: queueRequest(): Adjust buffer map empty error\n>>>>>>        message\n>>>>>>      libcamera: camera: queueBuffer(): Reject if it has buffers\n>>>>>>      apps: cam: Use camera buffer pool\n>>>>>>      app: lc-compliance: Use camera buffer pool\n>>>>>>      apps: lc-compliance: Add buffer pool tests\n>>>>>>      test: Use camera buffer pool\n>>>>>>      apps: qcam: Use camera buffer pool\n>>>>>>      v4l2: Use camera buffer pool\n>>>>>>      py: Use camera buffer pool\n>>>>>>      gstreamer: Use camera buffer pool\n>>>>>>      libcamera: request: Remove `ReuseFlag`\n>>>>>>      android: Update imported files\n>>>>>>      android: camera_request: Add helper for buffer conversion\n>>>>>>      android: camera_device: Move fence restoration into\n>>>>>>        `prepareToReturn()`\n>>>>>>      android: Use camera buffer pool\n>>>>>>      libcamera: request: Remove `addBuffer()`\n>>>>>>      test: fence: Enable\n>>>>>>\n>>>>>>     .../guides/application-developer.rst          |    9 -\n>>>>>>     Documentation/guides/pipeline-handler.rst     |   10 +-\n>>>>>>     .../libhardware/include/hardware/camera3.h    |  360 +-\n>>>>>>     .../include/hardware/camera_common.h          |  304 +-\n>>>>>>     .../libhardware/include/hardware/gralloc.h    |   99 +-\n>>>>>>     .../android/metadata/camera_metadata_hidden.h |   11 +-\n>>>>>>     .../android/metadata/system/camera_metadata.h |   41 +-\n>>>>>>     .../metadata/system/camera_metadata_tags.h    |  633 +-\n>>>>>>     .../metadata/system/camera_vendor_tags.h      |   10 +-\n>>>>>>     .../android/system/core/include/android/log.h |  450 +-\n>>>>>>     .../core/include/cutils/native_handle.h       |   62 +-\n>>>>>>     .../system/core/include/system/camera.h       |    4 +-\n>>>>>>     .../core/include/system/graphics-base-v1.2.h  |   36 +\n>>>>>>     .../core/include/system/graphics-base.h       |    1 +\n>>>>>>     .../system/core/include/system/graphics.h     |   10 +-\n>>>>>>     include/libcamera/camera.h                    |    5 +-\n>>>>>>     include/libcamera/framebuffer.h               |    1 -\n>>>>>>     include/libcamera/internal/camera.h           |   46 +-\n>>>>>>     include/libcamera/internal/framebuffer.h      |    6 +\n>>>>>>     include/libcamera/internal/pipeline_handler.h |   31 +-\n>>>>>>     include/libcamera/internal/request.h          |   24 +-\n>>>>>>     include/libcamera/request.h                   |   10 +-\n>>>>>>     src/android/camera3_hal.cpp                   |    3 +\n>>>>>>     src/android/camera_capabilities.cpp           |    3 +\n>>>>>>     src/android/camera_device.cpp                 |  287 +-\n>>>>>>     src/android/camera_device.h                   |    4 +\n>>>>>>     src/android/camera_hal_manager.cpp            |    2 +-\n>>>>>>     src/android/camera_ops.cpp                    |   16 +-\n>>>>>>     src/android/camera_request.cpp                |   53 +-\n>>>>>>     src/android/camera_request.h                  |   11 +-\n>>>>>>     src/android/metadata/camera_metadata.c        |  183 +-\n>>>>>>     .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n>>>>>>     src/apps/cam/camera_session.cpp               |   36 +-\n>>>>>>     src/apps/cam/camera_session.h                 |    2 +-\n>>>>>>     src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n>>>>>>     src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n>>>>>>     src/apps/qcam/main_window.cpp                 |   82 +-\n>>>>>>     src/apps/qcam/main_window.h                   |    1 -\n>>>>>>     src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n>>>>>>     src/libcamera/camera.cpp                      |  164 +-\n>>>>>>     src/libcamera/fence.cpp                       |   15 +-\n>>>>>>     src/libcamera/framebuffer.cpp                 |   57 +-\n>>>>>>     src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n>>>>>>     src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n>>>>>>     src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n>>>>>>     src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n>>>>>>     src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n>>>>>>     src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n>>>>>>     .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n>>>>>>     .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n>>>>>>     src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n>>>>>>     src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n>>>>>>     src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n>>>>>>     src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n>>>>>>     src/libcamera/pipeline_handler.cpp            |  260 +-\n>>>>>>     src/libcamera/request.cpp                     |  290 +-\n>>>>>>     src/py/cam/cam.py                             |   20 +-\n>>>>>>     src/py/examples/simple-cam.py                 |   13 +-\n>>>>>>     src/py/examples/simple-capture.py             |   20 +-\n>>>>>>     src/py/examples/simple-continuous-capture.py  |   32 +-\n>>>>>>     src/py/libcamera/py_main.cpp                  |   65 +-\n>>>>>>     src/v4l2/v4l2_camera.cpp                      |  150 +-\n>>>>>>     src/v4l2/v4l2_camera.h                        |   25 +-\n>>>>>>     src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n>>>>>>     src/v4l2/v4l2_camera_proxy.h                  |    3 -\n>>>>>>     test/camera/buffer_import.cpp                 |   22 +-\n>>>>>>     test/camera/camera_reconfigure.cpp            |   22 +-\n>>>>>>     test/camera/capture.cpp                       |   24 +-\n>>>>>>     test/camera/statemachine.cpp                  |    4 +-\n>>>>>>     test/fence.cpp                                |  214 +-\n>>>>>>     70 files changed, 9182 insertions(+), 1283 deletions(-)\n>>>>>>     create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n>>>>>>\n>>>>>> --\n>>>>>> 2.54.0\n>>>>\n>>","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 1439ABDE4C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Jul 2026 12:56:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F2B8167F0F;\n\tFri, 24 Jul 2026 14:56:03 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0386E67E89\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jul 2026 14:56:01 +0200 (CEST)","from [192.168.33.42] (185.182.215.156.nat.pool.zt.hu\n\t[185.182.215.156])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 4CA7D524;\n\tFri, 24 Jul 2026 14:55:00 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"GLm15zKb\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1784897700;\n\tbh=ay2M0AkuItIMA63BLpwW8qQBTYPtBl8EdRbCII8A3rI=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=GLm15zKbRn6Qfw/25o3LsiBK/sZlkCMZB8c1BwNg/myhPQIYYmRjnyjc+8adqKN9V\n\ttPdJuddgjXbiq9N280AKPPw2d8U3YCtHJ7ifcLTFk3/BK26HDxDW/uWuLm68fqVFak\n\t8FvslQzB7oh5/We/rH4LD6GezbO6KzTzym6lLqDg=","Message-ID":"<c7dd2055-f6cf-4a84-bf51-2fb59d9f2350@ideasonboard.com>","Date":"Fri, 24 Jul 2026 14:55:58 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"David Plowman <david.plowman@raspberrypi.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>\n\t<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>\n\t<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>\n\t<6tLdsPxodLNz3BDMEKU1_ZOQefpKwKapmLdAYPy8mlyZoh2gLSJF0_niM_9SMUK1C-zBMyPOFhMvo0PWN_ib7A==@protonmail.internalid>\n\t<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>\n\t<52279d34-59ec-4e62-b82b-04a40b784b41@ideasonboard.com>\n\t<CAHW6GYJna1S=1cP96O+MSUTCOhvYi_VRA62+xXUXr_JvhVZzJw@mail.gmail.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<CAHW6GYJna1S=1cP96O+MSUTCOhvYi_VRA62+xXUXr_JvhVZzJw@mail.gmail.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39840,"web_url":"https://patchwork.libcamera.org/comment/39840/","msgid":"<CAHW6GYKtkh8LQwVeBS80U_dCrA5uKugHiyU+dkWeCR-qy7zfCg@mail.gmail.com>","date":"2026-07-24T14:23:18","subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","submitter":{"id":42,"url":"https://patchwork.libcamera.org/api/people/42/","name":"David Plowman","email":"david.plowman@raspberrypi.com"},"content":"On Fri, 24 Jul 2026 at 13:56, Barnabás Pőcze\n<barnabas.pocze@ideasonboard.com> wrote:\n>\n> 2026. 07. 24. 14:02 keltezéssel, David Plowman írta:\n> > Hi again\n> >\n> > Sorry for asking another question!\n> >\n> > On Thu, 23 Jul 2026 at 16:42, Barnabás Pőcze\n> > <barnabas.pocze@ideasonboard.com> wrote:\n> >>\n> >> Hi\n> >>\n> >> 2026. 07. 23. 13:03 keltezéssel, David Plowman írta:\n> >>> Hi Barnabas\n> >>>\n> >>> Thanks for your replies.\n> >>>\n> >>> I think mostly I'm happy enough with things, though I wasn't quite\n> >>> clear why configure() has to empty the buffer pools (and you can't\n> >>> simply leave stuff in them), I obviously haven't quite understood\n> >>> something there.\n> >>\n> >> The thinking is that configuration most likely changes the size of the\n> >> resulting images, so leaving buffers that were created with the previous\n> >> configuration in mind could be problematic. It's simpler to just always\n> >> ensure that the pool is empty after configuration.\n> >>\n> >>\n> >>>\n> >>> The Android doc that you linked to was interesting, and is definitely\n> >>> an improvement. I've been complaining about this \"targeting specific\n> >>> buffers\" thing for years! It feels like libcamera will end up more\n> >>> like Android once all this has been done. I note that Android appears\n> >>> to make no allowance for the\n> >>> controls-stuck-at-the-back-of-the-request-queue problem, so I'd be\n> >>> interested to hear what folks think about that.\n> >>>\n> >>> Finally, is there any chance of getting any more visibility of the new\n> >>> API? In particular, seeing a minimal \"start-camera-and-request-frames\"\n> >>> application might make it all feel a bit more concrete!\n> >>\n> >> Most things remain the same, the main conceptual difference is that\n> >> `Camera::addBuffer()` needs to be called to provide the buffers,\n> >> and the targeted streams must be explicitly enabled in a request\n> >> with `Request::enableStream()`\n> >\n> > Something was bothering me a bit here, and it finally dawned on me what it was.\n> >\n> > In the Android world, where control lists are synchronised with the\n> > request you put them in, this seems fine.\n> >\n> > However, if you want to be able to send control lists that bypass the\n> > request queue, then you have no way to synchronise the enabling of a\n> > buffer with that control list.\n> >\n> > So the most obvious example is if I'm running with, say, 16 requests\n> > circulating, because I have a Pi that's busy or slow and I don't want\n> > to drop frames. Now I want to do a capture with exposure X and enable\n> > a buffer for my high resolution stream for that capture (for which I\n> > am not normally enabling buffers). I have no way to send my control\n> > \"early\" and enable a buffer for it. (Instead, the whole system would\n> > be forced to work in \"Android mode\", and you'd have to submit a\n> > request and wait 16 frames for your buffer to arrive. Ouch!)\n>\n> That's true, but unless I'm missing something, this would be a limitation if one\n> just added control queues even with the current model (request has buffers), no?\n>\n> And just so I don't misunderstand, the requirement is to be able to fast-track controls\n> in a way that enables the application to also capture arbitrary streams from the (first)\n> frame on which the fast-tracked controls were in effect?\n>\n> >\n> > The obvious answer would seem to be that enabling buffers should be a\n> > control. In the Android world that would work just the same, because\n> > they're synchronised, but it would also enable the use case above\n> > that's important to us. Or one could let applications do it either\n> > way, I suppose.\n> >\n> > Any thoughts?\n>\n> Given that a `Request` is a collection of controls and enabled streams, wouldn't it\n> make sense to have a way to fast-track a request?\n\nThat's certainly an idea. In my example I used just a single capture,\nbut of course the real target is burst captures. Some things to figure\nout:\n\n* If I already have 15 requests queued up, how do I get all my burst\ncaptures to the head of the queue (in the right order)?\n* I probably don't have enough requests for all the burst captures\nthat I want to queue, which is just awkward (compared to control\nlists).\n* There might be previous \"fast track\" requests in the queue which I\nneed to stay behind.\n\nSo it still feels like a bit of a two queue problem to me?\n\n>\n> If there is a separate `ControlList` queue and streams are passed as a control, it's\n> not clear to me how one could select the request to complete with the buffers and how\n> one would reconcile potential conflicts wrt. the enabled streams and controls in that\n> request. I suppose maybe the enabled streams lists could just be merged.\n\nActually I see the argument for having control lists in requests as\nwell, then folks can use the system however they like. I'm not\nbothered by \"conflicts\" when merging stuff, if applications are\nfiddling with the same controls or settings in different places,\nthat's just an error and we can do what we like!\n\nDavid\n\n>\n> Or am I misunderstanding something?\n>\n>\n> >\n> > Thanks!\n> > David\n> >\n> >>\n> >> The most straightforward way to convert an application would be something like this:\n> >>     * replace `Request::addBuffer()` with a combination of:\n> >>       - `Camera::addBuffer()`\n> >>       - `Request::enableStream()`\n> >>     * replace `Request::reuse(ReuseBuffers)` with a combination of:\n> >>       - `Camera::addBuffer()` for each buffer in the request\n> >>       - `Request::reuse()`\n> >>       - `Request::enableStream()` for each target stream\n> >>\n> >> I believe patch \"py: Use camera buffer pool\" (especially src/py/examples/simple-cam.py)\n> >> should showcase the minimal \"start-camera-and-request-frames\" application\n> >> you're looking for (albeit in python, not C++). But let me know if you need a better example.\n> >> In any case, if the details of the API are finalized, https://gitlab.freedesktop.org/camera/simple-cam\n> >> will be updated to reflect the changes.\n> >>\n> >> The only complication is that `Camera::addBuffer()` is only allowed after `Camera::start()`.\n> >> And there are some unsure details still, specifically related to how buffers\n> >> can / cannot be returned without a request (i.e. how can a pipeline handler\n> >> \"reject\" a buffer and how can the application recognize that).\n> >>\n> >>\n> >> Regards,\n> >> Barnabás Pőcze\n> >>\n> >>>\n> >>> Thanks\n> >>> David\n> >>>\n> >>> On Fri, 3 Jul 2026 at 15:37, Barnabás Pőcze\n> >>> <barnabas.pocze@ideasonboard.com> wrote:\n> >>>>\n> >>>> Hi\n> >>>>\n> >>>> I have tried to answer the questions, let me know if I'd missed anything.\n> >>>>\n> >>>> 2026. 07. 03. 14:37 keltezéssel, David Plowman írta:\n> >>>>> Hi Barnabas\n> >>>>>\n> >>>>> Thanks for working on all this, very excited to see progress on this topic!\n> >>>>>\n> >>>>> Unfortunately I'm about to disappear on holiday for 2 weeks, so this\n> >>>>> reply is going to turn into a long list of questions that I've not had\n> >>>>> a huge amount of time to think about, so apologies in advance for\n> >>>>> that.\n> >>>>>\n> >>>>> On Mon, 29 Jun 2026 at 17:30, Barnabás Pőcze\n> >>>>> <barnabas.pocze@ideasonboard.com> wrote:\n> >>>>>>\n> >>>>>> This is the first RFC changeset for splitting requests and buffers. It largely\n> >>>>>> includes https://patchwork.libcamera.org/cover/26964/, but many of those are\n> >>>>>> already reviewed.\n> >>>>>>\n> >>>>>> The \"interesting\" changes start with \"test: fence: Disable temporarily\".\n> >>>>>>\n> >>>>>> ---\n> >>>>>>\n> >>>>>> # introduction\n> >>>>>>\n> >>>>>> The basic idea is that requests no longer have buffers when they are submitted,\n> >>>>>> and the camera keeps track of a set of buffers for each stream, and buffers will\n> >>>>>> be attached to requests from this pool in an unspecified order\n> >>>>>>\n> >>>>>> A new function, `Camera::addBuffer(stream, buffer, fence)` is added to fill the pool;\n> >>>>>> this can be called in the \"Running\" state. `Camera::stop()` empties the pool via the\n> >>>>>> `bufferCompleted` event. Another new function, `Request::enableStream(stream, bool)`\n> >>>>>> is used to set which streams a request wants frames from.\n> >>>>>\n> >>>>> I guess I'm vaguely expecting the buffer pool mechanism to be to a\n> >>>>> large extent separate from the camera system. So the camera system\n> >>>>> will obviously be a client of it, but otherwise they're not really\n> >>>>> intertwined. Is that likely to be the case here? Or maybe it's not\n> >>>>> possible.\n> >>>>\n> >>>> The buffer pool mechanism is implemented in the \"Camera\" and related types.\n> >>>> And not in e.g. a separate `BufferPool` type. This was deemed the simpler\n> >>>> approach. But there are no technical obstacles as far as I can tell.\n> >>>> Or do you mean something else?\n> >>>>\n> >>>>\n> >>>>>\n> >>>>> I'm also vaguely feeling an application might want to control the\n> >>>>> lifetime of the pool and contents. For example, when the camera is\n> >>>>> stopped, maybe you want to leave your buffers in the pool so that you\n> >>>>> can simply restart it? Wasn't sure if that kind of behaviour is\n> >>>>> envisaged here.\n> >>>>\n> >>>> I don't think that option was discussed, but could be implemented.\n> >>>> Nonetheless then `configure()` has to clear the pool in any case,\n> >>>> which is technically a bit more complicated to do.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>>>\n> >>>>>> Pipeline handlers can use `Camera::Private::acquireBuffer(stream)` to retrieve a\n> >>>>>> buffer for the given stream. If this buffer is not acceptable, then\n> >>>>>> `Camera::Private::rejectBuffer(buffer)` can be used to reject it. Otherwise\n> >>>>>> `completeBuffer(request, buffer)` is used normally to attach it to a request.\n> >>>>>>\n> >>>>>> This new behaviour is opt-in for pipeline handlers for now, with no opt-in,\n> >>>>>> the `PipelineHandler` base class fills each request with buffers before\n> >>>>>> calling `queueRequestDevice()`.\n> >>>>>\n> >>>>> One thing I raised a while back was whether there are applications\n> >>>>> that want to target specific buffers at particular requests. I'm\n> >>>>> thinking of Android here, though Android remains a giant mystery to\n> >>>>> me. But maybe another application might have a reason to do that?\n> >>>>\n> >>>> Android has caused quite a bit of headache, so in the end a switch\n> >>>> to their \"new\" buffer model was made: https://source.android.com/docs/core/camera/buffer-management-api\n> >>>>\n> >>>> This uses a similar pool based approach where requests no longer contain any buffers.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>> The thought was to leave *optional* buffers in request. If it's there,\n> >>>>> you use it and otherwise the camera system goes to the buffer pool to\n> >>>>> get one. It sort of feels to me like it should be doable, but is it\n> >>>>> useful?\n> >>>>>\n> >>>>> I used to wonder whether an application might want to hold back a\n> >>>>> number of buffers so that it could do a burst capture, guaranteeing to\n> >>>>> have a buffer for every request. But I'm not so convinced by that,\n> >>>>> presumably you can check if you have enough buffers in the pool.\n> >>>>>\n> >>>>> Though having optional buffers would certainly ease migration to the new scheme!\n> >>>>\n> >>>> I don't have a satisfactory answer unfortunately. I think it's a matter\n> >>>> of making a decision, it seems technically feasible. Of course it would\n> >>>> complicate the core and pipeline handler parts.\n> >>>>\n> >>>> There is also a question of how to handle requests that mix both:\n> >>>> having some buffers and also some \"just\" enabled streams. Then\n> >>>> fences must also not be forgotten about. And then it has to be evaluated\n> >>>> how many technical difficulties supporting this mixed model would cause for\n> >>>> the existing pipeline handler implementations.\n> >>>>\n> >>>> An earlier prototype explored the idea of automatically adding buffers\n> >>>> from requests to the pool when they are queued. This of course would\n> >>>> break the association between buffers and requests, so it wouldn't\n> >>>> address your point. And it was decided not to go forward with this\n> >>>> compatibility behaviour in any case.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>>>\n> >>>>>>\n> >>>>>> # discussion points\n> >>>>>>\n> >>>>>> ## adding buffers before `Camera::start()`\n> >>>>>>\n> >>>>>> Currently buffers can only be added in the \"Running\" state. They could\n> >>>>>> be added in \"Configured\" as well, but there is no \"unconfigure\" function,\n> >>>>>> and putting it into `stop()` would be a bit asymmetric.\n> >>>>>\n> >>>>> Indeed, I've always wanted to queue requests before starting the camera!\n> >>>>>\n> >>>>>>\n> >>>>>> ## empty pool notification\n> >>>>>>\n> >>>>>> Currently there is no mechanism for the application to know how many\n> >>>>>> buffers it should keep in the pool. I think a signal to notify the application\n> >>>>>> when it should add more buffers for a given stream could be added. But the\n> >>>>>> main idea was to expose some kind of minimum buffer count quantity.\n> >>>>>>\n> >>>>>> ## requirements towards application wrt. buffers\n> >>>>>>\n> >>>>>> With this prototype, an application is essentially required to always process *all*\n> >>>>>> buffers in *all* completed requests, otherwise it might lose buffers. (This\n> >>>>>> applies to cancelled requests as well.) Is that reasonable?\n> >>>>>\n> >>>>> I think it sounds OK to expect applications to manage buffers, at\n> >>>>> least to an extent. As I remarked above, I think maybe applications\n> >>>>> will want to manage buffers for their own convenience.\n> >>>>>\n> >>>>>>\n> >>>>>> ## returning unused buffers\n> >>>>>>\n> >>>>>> Currently this is done from `Camera::stop()` with the `bufferCompleted` signal\n> >>>>>> where `request == nullptr`. This works, but may not be the best interface.\n> >>>>>>\n> >>>>>> ## returning rejected buffers\n> >>>>>>\n> >>>>>> Pipeline handlers can reject buffers. But how should that be signalled to the\n> >>>>>> application. Currently this is also done via `bufferCompleted` with `request == nullptr`.\n> >>>>>> But this is not ideal because there isn't really a way to distinguish it from\n> >>>>>> an unused buffer since both are returned with `FrameMetadata::Status::FrameCancelled`\n> >>>>>> because `FrameError` requires some other fields to be valid.\n> >>>>>>\n> >>>>>> ## extending `completeBuffer()` with stream parameter\n> >>>>>>\n> >>>>>> Initially I planned to add a stream parameter to `completeBuffer()`, but most pipeline handlers\n> >>>>>> are not trivially convertible, especially something like `imx8-isi`. So I simply went ahead\n> >>>>>> with storing the associated stream in the `FrameBuffer` itself for now. I still think having\n> >>>>>> `completeBuffer(req, stream, buf)` is worthwhile, but it is not a \"natural\" change at the moment.\n> >>>>>\n> >>>>> It does feel a bit strange to me that buffers should know about\n> >>>>> streams, and so on. I think I was expecting buffers/pools to be\n> >>>>> largely independent of such things. But I accept there might be a good\n> >>>>> reason.\n> >>>>\n> >>>> Indeed they shouldn't. But migrating straight to `completeBuffer(req, stream, buf)`\n> >>>> world where buffers have no idea about requests and streams\n> >>>> is not as simple as I would have liked. Especially since most\n> >>>> pipeline handlers are written with the current model in mind\n> >>>> where a buffer is already in a request associated with a stream.\n> >>>> And so the actual stream is not even easily available at buffer\n> >>>> completion time in many cases. So this is a compromise.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>>>\n> >>>>>> ## fence timeout\n> >>>>>>\n> >>>>>> Previously a hard-coded timeout was used for fences. This is now removed.\n> >>>>>> Should there be a hard-coded fixed timeout for fences?\n> >>>>>>\n> >>>>>>\n> >>>>>> # TODO\n> >>>>>>\n> >>>>>> # converting more pipeline handlers\n> >>>>>>\n> >>>>>> Only the uvcvideo pipeline handler is converted to use the buffer pool\n> >>>>>> directly as an experiment, but more should be converted to really see\n> >>>>>> if this public api is a good fit for pipeline handlers. Especially something\n> >>>>>> like `imx8-isi` since that has a bit different architecture from the others.\n> >>>>>>\n> >>>>>> # minimum buffer count\n> >>>>>>\n> >>>>>> The applications need to know how many buffers should be kept in the pool\n> >>>>>> for a given stream for continuous streaming. This should be a property or\n> >>>>>> similar.\n> >>>>>\n> >>>>> Yes, I guess so. In practice we always allocate way more than the\n> >>>>> minimum, simply because that avoids frame drops.\n> >>>>\n> >>>> Yes, but this information can be useful if the buffer goes into a processing pipeline\n> >>>> that holds on to it, or if the applications creates its own `FrameBuffer`s without\n> >>>> the `FrameBufferAllocator`.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>>>\n> >>>>>> # `FrameBuffer::Private::request()`\n> >>>>>>\n> >>>>>> After all pipeline handlers are migrated, the request member of `FrameBuffer`\n> >>>>>> should probably be removed to fully decouple the two.\n> >>>>>\n> >>>>> One other slightly unusual use case I'd like to add into the mix is\n> >>>>> one I remember hearing on a Kamaros call. There's a stream of frames\n> >>>>> coming back from a camera, but then there's a second stream, made from\n> >>>>> the same sensor images, but which is generated only occasionally (so\n> >>>>> runs at a lower framerate).\n> >>>>>\n> >>>>> Does the buffer pool mechanism give us a way to handle this? When a\n> >>>>> request completes there could be 3 outcomes - 1. here's your buffer,\n> >>>>> 2. sorry, there wasn't a buffer in the pool, and now 3. there wasn't\n> >>>>> actually a frame generated for this stream on this occasion.\n> >>>>\n> >>>> You mean like a stream that might not supply a frame even if the\n> >>>> request enables it, there are available buffers, and no errors\n> >>>> are encountered? Or put differently, a stream that \"itself\" decides\n> >>>> when to supply frames regardless of the streams in the request?\n> >>>>\n> >>>> In that case currently (2) and (3) cannot be differentiated. But\n> >>>> it's a matter of extending the buffer map in the request.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>> The final thing I'd like to discuss is how this relates to control\n> >>>>> queues. Of course, strictly speaking the two subjects are independent,\n> >>>>> but nonetheless I have a couple of questions.\n> >>>>>\n> >>>>> * The buffer/request split will obviously break the existing API and\n> >>>>> cause a certain amount of work. If we're going to have control queues,\n> >>>>> are we going to break everything again later, or do it all at once?\n> >>>>> Just wondering...\n> >>>>\n> >>>> I suppose it would be better to break the world once, but I'm no\n> >>>> authority on the question of libcamera stability and releases.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>> * If you took control lists out of requests you might find there's\n> >>>>> almost nothing left in them. Wanted to check we're OK with that just\n> >>>>> in case we were to end up there!\n> >>>>\n> >>>> I think it's fine. A request would still have a \"cookie\" and the set\n> >>>> of enabled streams. And it has a sequence number, status, a set of\n> >>>> buffers, and a set of metadata items when it completes.\n> >>>>\n> >>>> Nonetheless we could explore getting rid of the application facing\n> >>>> `Request` type and using something different, maybe something more\n> >>>> centered around using the numeric sequence number as the identity.\n> >>>>\n> >>>>\n> >>>>>\n> >>>>> Anyway, apologies for the big dump of questions and then running away.\n> >>>>> Look forward to hearing more on the subject!\n> >>>>>\n> >>>>> Thanks\n> >>>>> David\n> >>>>>\n> >>>>>>\n> >>>>>> ---\n> >>>>>>\n> >>>>>> Barnabás Pőcze (54):\n> >>>>>>      apps: cam: Simplify buffer reuse\n> >>>>>>      libcamera: request: Disassociate buffer when cancelling\n> >>>>>>      libcamera: pipeline: Replace open-coded request cancellation\n> >>>>>>      libcamera: pipeline: mali-c55: Remove `setRequest()` calls\n> >>>>>>      libcamera: pipeline: virtual: Make copy of request's buffer map\n> >>>>>>      libcamera: request: completeBuffer(): Emit `bufferCompleted` here\n> >>>>>>      libcamera: pipeline_handler: completeBuffer(): Inline and `static`\n> >>>>>>      v4l2: v4l2_camera: Avoid a level of indirection\n> >>>>>>      v4l2: v4l2_camera: Remove repated index checks\n> >>>>>>      v4l2: v4l2_camera_proxy: Remove `bufferCount_`\n> >>>>>>      v4l2: v4l2_camera: Use actually allocated buffer count\n> >>>>>>      v4l2: v4l2_camera: Use buffer cookie for indexing\n> >>>>>>      v4l2: v4l2_camera: Rename `Buffer` to `CompletedBuffer`\n> >>>>>>      v4l2: v4l2_camera: Always clear pending requests\n> >>>>>>      v4l2: v4l2_camera: Clear completed requests when stopping\n> >>>>>>      v4l2: v4l2_camera: Provide buffers one by one\n> >>>>>>      test: fence: Disable temporarily\n> >>>>>>      libcamera: request: Remove `ReuseBuffers`\n> >>>>>>      libcamera: framebuffer: request(): Move to private type\n> >>>>>>      libcamera: framebuffer: Store associated Stream\n> >>>>>>      libcamera: camera: Add `StreamData`\n> >>>>>>      libcamera: camera: Add buffer pool\n> >>>>>>      libcamera: request: addBuffer(): Remove impl\n> >>>>>>      libcamera: request: Remove fence support\n> >>>>>>      libcamera: request: Store count of pending buffers\n> >>>>>>      libcamera: request: doCancelRequest(): Remove\n> >>>>>>      libcamera: pipeline_handler: Move constructor options to a separate\n> >>>>>>        type\n> >>>>>>      libcamera: pipeline_handler: Acquire buffers if not using pool\n> >>>>>>      libcamera: request: enableStream(): Add\n> >>>>>>      libcamera: camera: acquireBuffer(): Add\n> >>>>>>      libcamera: camera: rejectBuffer(): Add\n> >>>>>>      libcamera: pipeline_handler: buffersAddedDevice(): New virtual\n> >>>>>>        function\n> >>>>>>      libcamera: pipeline_handler: Use `std::deque`\n> >>>>>>      libcamera: pipeline_handler: completeRequest(): Return request count\n> >>>>>>      libcamera: pipeline: uvcvideo: Use buffer pool prototype\n> >>>>>>      libcamera: request: completeBuffer(): Emit `bufferCompleted` last\n> >>>>>>      libcamera: camera: bufferCompleted: Pass `Stream` as well\n> >>>>>>      libcamera: camera: queueRequest(): Adjust buffer map empty error\n> >>>>>>        message\n> >>>>>>      libcamera: camera: queueBuffer(): Reject if it has buffers\n> >>>>>>      apps: cam: Use camera buffer pool\n> >>>>>>      app: lc-compliance: Use camera buffer pool\n> >>>>>>      apps: lc-compliance: Add buffer pool tests\n> >>>>>>      test: Use camera buffer pool\n> >>>>>>      apps: qcam: Use camera buffer pool\n> >>>>>>      v4l2: Use camera buffer pool\n> >>>>>>      py: Use camera buffer pool\n> >>>>>>      gstreamer: Use camera buffer pool\n> >>>>>>      libcamera: request: Remove `ReuseFlag`\n> >>>>>>      android: Update imported files\n> >>>>>>      android: camera_request: Add helper for buffer conversion\n> >>>>>>      android: camera_device: Move fence restoration into\n> >>>>>>        `prepareToReturn()`\n> >>>>>>      android: Use camera buffer pool\n> >>>>>>      libcamera: request: Remove `addBuffer()`\n> >>>>>>      test: fence: Enable\n> >>>>>>\n> >>>>>>     .../guides/application-developer.rst          |    9 -\n> >>>>>>     Documentation/guides/pipeline-handler.rst     |   10 +-\n> >>>>>>     .../libhardware/include/hardware/camera3.h    |  360 +-\n> >>>>>>     .../include/hardware/camera_common.h          |  304 +-\n> >>>>>>     .../libhardware/include/hardware/gralloc.h    |   99 +-\n> >>>>>>     .../android/metadata/camera_metadata_hidden.h |   11 +-\n> >>>>>>     .../android/metadata/system/camera_metadata.h |   41 +-\n> >>>>>>     .../metadata/system/camera_metadata_tags.h    |  633 +-\n> >>>>>>     .../metadata/system/camera_vendor_tags.h      |   10 +-\n> >>>>>>     .../android/system/core/include/android/log.h |  450 +-\n> >>>>>>     .../core/include/cutils/native_handle.h       |   62 +-\n> >>>>>>     .../system/core/include/system/camera.h       |    4 +-\n> >>>>>>     .../core/include/system/graphics-base-v1.2.h  |   36 +\n> >>>>>>     .../core/include/system/graphics-base.h       |    1 +\n> >>>>>>     .../system/core/include/system/graphics.h     |   10 +-\n> >>>>>>     include/libcamera/camera.h                    |    5 +-\n> >>>>>>     include/libcamera/framebuffer.h               |    1 -\n> >>>>>>     include/libcamera/internal/camera.h           |   46 +-\n> >>>>>>     include/libcamera/internal/framebuffer.h      |    6 +\n> >>>>>>     include/libcamera/internal/pipeline_handler.h |   31 +-\n> >>>>>>     include/libcamera/internal/request.h          |   24 +-\n> >>>>>>     include/libcamera/request.h                   |   10 +-\n> >>>>>>     src/android/camera3_hal.cpp                   |    3 +\n> >>>>>>     src/android/camera_capabilities.cpp           |    3 +\n> >>>>>>     src/android/camera_device.cpp                 |  287 +-\n> >>>>>>     src/android/camera_device.h                   |    4 +\n> >>>>>>     src/android/camera_hal_manager.cpp            |    2 +-\n> >>>>>>     src/android/camera_ops.cpp                    |   16 +-\n> >>>>>>     src/android/camera_request.cpp                |   53 +-\n> >>>>>>     src/android/camera_request.h                  |   11 +-\n> >>>>>>     src/android/metadata/camera_metadata.c        |  183 +-\n> >>>>>>     .../metadata/camera_metadata_tag_info.c       | 5478 ++++++++++++++++-\n> >>>>>>     src/apps/cam/camera_session.cpp               |   36 +-\n> >>>>>>     src/apps/cam/camera_session.h                 |    2 +-\n> >>>>>>     src/apps/lc-compliance/helpers/capture.cpp    |   23 +-\n> >>>>>>     src/apps/lc-compliance/tests/capture_test.cpp |  261 +\n> >>>>>>     src/apps/qcam/main_window.cpp                 |   82 +-\n> >>>>>>     src/apps/qcam/main_window.h                   |    1 -\n> >>>>>>     src/gstreamer/gstlibcamerasrc.cpp             |  136 +-\n> >>>>>>     src/libcamera/camera.cpp                      |  164 +-\n> >>>>>>     src/libcamera/fence.cpp                       |   15 +-\n> >>>>>>     src/libcamera/framebuffer.cpp                 |   57 +-\n> >>>>>>     src/libcamera/pipeline/imx8-isi/imx8-isi.cpp  |    5 +-\n> >>>>>>     src/libcamera/pipeline/ipu3/ipu3.cpp          |   16 +-\n> >>>>>>     src/libcamera/pipeline/mali-c55/mali-c55.cpp  |    7 +-\n> >>>>>>     src/libcamera/pipeline/mali-c55/rzg2l-cru.cpp |    3 +-\n> >>>>>>     src/libcamera/pipeline/mali-c55/rzg2l-cru.h   |    3 +-\n> >>>>>>     src/libcamera/pipeline/rkisp1/rkisp1.cpp      |    7 +-\n> >>>>>>     .../pipeline/rpi/common/pipeline_base.cpp     |   16 +-\n> >>>>>>     .../pipeline/rpi/common/pipeline_base.h       |    2 +-\n> >>>>>>     src/libcamera/pipeline/simple/simple.cpp      |   17 +-\n> >>>>>>     src/libcamera/pipeline/uvcvideo/uvcvideo.cpp  |   72 +-\n> >>>>>>     src/libcamera/pipeline/vimc/vimc.cpp          |   11 +-\n> >>>>>>     src/libcamera/pipeline/virtual/virtual.cpp    |   44 +-\n> >>>>>>     src/libcamera/pipeline_handler.cpp            |  260 +-\n> >>>>>>     src/libcamera/request.cpp                     |  290 +-\n> >>>>>>     src/py/cam/cam.py                             |   20 +-\n> >>>>>>     src/py/examples/simple-cam.py                 |   13 +-\n> >>>>>>     src/py/examples/simple-capture.py             |   20 +-\n> >>>>>>     src/py/examples/simple-continuous-capture.py  |   32 +-\n> >>>>>>     src/py/libcamera/py_main.cpp                  |   65 +-\n> >>>>>>     src/v4l2/v4l2_camera.cpp                      |  150 +-\n> >>>>>>     src/v4l2/v4l2_camera.h                        |   25 +-\n> >>>>>>     src/v4l2/v4l2_camera_proxy.cpp                |  118 +-\n> >>>>>>     src/v4l2/v4l2_camera_proxy.h                  |    3 -\n> >>>>>>     test/camera/buffer_import.cpp                 |   22 +-\n> >>>>>>     test/camera/camera_reconfigure.cpp            |   22 +-\n> >>>>>>     test/camera/capture.cpp                       |   24 +-\n> >>>>>>     test/camera/statemachine.cpp                  |    4 +-\n> >>>>>>     test/fence.cpp                                |  214 +-\n> >>>>>>     70 files changed, 9182 insertions(+), 1283 deletions(-)\n> >>>>>>     create mode 100644 include/android/system/core/include/system/graphics-base-v1.2.h\n> >>>>>>\n> >>>>>> --\n> >>>>>> 2.54.0\n> >>>>\n> >>\n>","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 BFB47BDE4C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Jul 2026 14:23:33 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C1F7F67F1E;\n\tFri, 24 Jul 2026 16:23:32 +0200 (CEST)","from mail-ed1-x529.google.com (mail-ed1-x529.google.com\n\t[IPv6:2a00:1450:4864:20::529])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A98EA67E89\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jul 2026 16:23:30 +0200 (CEST)","by mail-ed1-x529.google.com with SMTP id\n\t4fb4d7f45d1cf-6986287534eso678838a12.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jul 2026 07:23:30 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"SiWhee9O\"; dkim-atps=neutral","ARC-Seal":"i=1; a=rsa-sha256; t=1784903010; cv=none;\n\td=google.com; s=arc-20260327;\n\tb=Yy5khVFuuVxx0dUr5gQEjd7UzPegJcE/03FlQ0DB9NAVIvB7qYrg2JGYlOH/VGB/6r\n\tTidM2XLVcf3nC/fn5wdl6N1mho/+xlrawB1SL8C9v88WANLRz+tKG7NmTNWcaUCWDvv/\n\tItZpxOhKZJOQTijUHOQ7SceOp9iFmL0TqJmemzaXOsmjlD7fYY2joxNNro2AhKF4E5sX\n\tVHUrZTtUbqTQjs6MkfBlj8eu6GFtCQ+6Sat+uNVGCpT2ZWply8IjF8+RRIkW9KeDc/a7\n\tlqhrHPToKelAD4K/G79z883d7dDJQ7khpYYVJDu9yGF6mFnVpvjXlvWU8UyB0i0kMqpj\n\tg+aA==","ARC-Message-Signature":"i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n\ts=arc-20260327; \n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:dkim-signature;\n\tbh=dbbNtDR5osV0gETBxkBjKWD5Mehj6adBh+Dwe2R4674=;\n\tfh=6eMZ9Peh5oKJMXVlU5do7GxLXGl0cSCd64pkjvWpyo4=;\n\tb=pelYwC8naOm2qsA9IFJxqMaRY/FCsxuu7MLIuVOXDtXuH3+pHzZRZhCQOd9Iu7ZMZl\n\tRhawPFyJiY25KNEfXwygJVrk/XuG8rl9MP+1Td0BwmWXtfdBUhz4h5K+tk9YY5HmNjk6\n\tg4ix9/HhOE5rnkjh+JuHEtxPa4CKLDIidGgxv3e6Rd7G00LFmdr993Xm+OAD6F9k9dJo\n\tuwCoVNIFpowMona9JpWBkE3Zbj7hdD4SqEh+nmVknTysTGfhzOBhBsyHFVg4OZXbJk8S\n\tKkvl+BcFxgxf3eqBZQcWFMLTbDrhWmspY0pcT3mtGOhKwyKVhrPWDMBIyahFeYEiuEdc\n\tFT3Q==; darn=lists.libcamera.org","ARC-Authentication-Results":"i=1; mx.google.com; arc=none","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1784903010; x=1785507810;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:from:to:cc:subject\n\t:date:message-id:reply-to:content-type;\n\tbh=dbbNtDR5osV0gETBxkBjKWD5Mehj6adBh+Dwe2R4674=;\n\tb=SiWhee9OvH9jrFp3QwwL+iHlJMmfoRhNXRgBb6Xcy7/80mb8Cmx/gvB08NlKNe/D0D\n\tafQzyBopeqv8sIcfrZoDlUgvb48VGfism8A962cmmM36KJ4eiL95aejqye37spN9OOB7\n\t/b9Nuee1aKmSaG7XAQsi+Wzh9qVWx1vo+2WJXcc7sdecVz6yxLaeIzj0W2GGKXwyMRjr\n\tK0CLIx8YsyxMj8h80VG8Tr+p/TFoYzoK6Hgxrj04XwZyzL56BVdcUDPmwmCPvWHv3V1U\n\tYciJW6cY2yN5hZRWA4Q9eWHlKrcqVGfxqgwgMJ5A5GPNwfodtGI5/E6j/I7TuT6qJmHD\n\tOX/Q==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784903010; x=1785507810;\n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to\n\t:content-type;\n\tbh=dbbNtDR5osV0gETBxkBjKWD5Mehj6adBh+Dwe2R4674=;\n\tb=ZpMJSRo4/B+VLhqqkSTd1tCGQkuiTGmVxaN//THlCTjzOV/doeVZDfiAPcrDpIv7Vh\n\tfmWSu1TF7rbsa5Lg0ZmNYGxRLVdKujI2jUc34AOcLY35I6NccyipsF5WJoJ3WOpUT4aY\n\tIsg9A4fb1oUWMbRO9nbhP8y3TBrCncL/NvzxkZKUaWYHemXwXGxvj7T0e+nFxQh6auTV\n\tnvXeaGo9QV3+It6YtyV73LWAH+WPbboXwpV7/gBmD8bSfzC1wsCKjUWjrvXhQoyw/Uua\n\tMIn1S5aFFZwJCZ5v7nR8W0IuAjdoYx6e6gCyKlPQAgpVA9ygrmmaKsbspByChngm8Svf\n\tK6rA==","X-Gm-Message-State":"AOJu0YxQu0FqNKNhGgCIyZgHzrYLCxGTFVSRgJiYRuc5jibHYByFhzbm\n\tdm+6aXf1/TtnRFe7SSOSw0k4LEDvOe037MEGWFpvH44ybFDgi7Cg6dp9P0GNclXfE+02cxHMgvl\n\tqxtkZObezmo5p6g6YLfpbirs93XQQNK8d+9aV9ZC2Nw==","X-Gm-Gg":"AR+sD110fsMymr2xmh2/63QdcAqKxUdAdpVJSV2sqY2QOaqSz2tb7M65jiqggDtiK/p\n\tAQCdfFPiNI4qdb49M9v4ByKW58yXXZHErBjPZEevrbwIhzJBQ3pHTXu9EBGG49yS/kZBzq39PpW\n\trbGqvWONUc2CSBmUKtTWQLKXQLf6LP9kei6yWp4ZLJxJ5BTy6bHdV62Ocbi1B1ItKN+kWnlRuDL\n\t8xAtGzb0TQTBvU3DNbqMCTuQ4rMeLkWhuQQwGBAyKb18exlRso0onhZl0gis8jmZM9bW8hcJajy\n\t6Nvw9RbB/JJ4z880QxnJ5Kw4c84ZMDAgfxHOJhUY653Ltn9D7TdGkSH0wC58EYjG9ivZUnArWvs\n\toUg==","X-Received":"by 2002:a05:6402:5054:b0:69c:6e8d:dda7 with SMTP id\n\t4fb4d7f45d1cf-69f6cd0c94bmr2674121a12.12.1784903009828;\n\tFri, 24 Jul 2026 07:23:29 -0700 (PDT)","MIME-Version":"1.0","References":"<20260629163017.863145-1-barnabas.pocze@ideasonboard.com>\n\t<CAHW6GY+NvhE9dGTVuDgvRtdY-3DNknUmGgt_z+M8tm+cQvoEzA@mail.gmail.com>\n\t<570fddd8-7727-4068-a0db-0603c31584b5@ideasonboard.com>\n\t<6tLdsPxodLNz3BDMEKU1_ZOQefpKwKapmLdAYPy8mlyZoh2gLSJF0_niM_9SMUK1C-zBMyPOFhMvo0PWN_ib7A==@protonmail.internalid>\n\t<CAHW6GYK6-gpqH=cd1uffB716abgEwpSaMSVOEzF69Q+YTEV3aw@mail.gmail.com>\n\t<52279d34-59ec-4e62-b82b-04a40b784b41@ideasonboard.com>\n\t<CAHW6GYJna1S=1cP96O+MSUTCOhvYi_VRA62+xXUXr_JvhVZzJw@mail.gmail.com>\n\t<c7dd2055-f6cf-4a84-bf51-2fb59d9f2350@ideasonboard.com>","In-Reply-To":"<c7dd2055-f6cf-4a84-bf51-2fb59d9f2350@ideasonboard.com>","From":"David Plowman <david.plowman@raspberrypi.com>","Date":"Fri, 24 Jul 2026 15:23:18 +0100","X-Gm-Features":"AUfX_mwNThJEaZ8U9USDjwoSrOO-uTczdrtSrCr7RzaoCNex3iKn2P1hmxjbAMA","Message-ID":"<CAHW6GYKtkh8LQwVeBS80U_dCrA5uKugHiyU+dkWeCR-qy7zfCg@mail.gmail.com>","Subject":"Re: [RFC PATCH v1 00/54] libcamera: Split requests and buffers","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","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>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]