Show a patch.

GET /api/patches/2270/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2270,
    "url": "https://patchwork.libcamera.org/api/patches/2270/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/2270/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20191028022525.796995-11-niklas.soderlund@ragnatech.se>",
    "date": "2019-10-28T02:25:23",
    "name": "[libcamera-devel,RFC,10/12] libcamera: buffer: Store buffer information in separate container",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "a58ebd54f2f21cac78df14da4feb177b69e203c6",
    "submitter": {
        "id": 5,
        "url": "https://patchwork.libcamera.org/api/people/5/?format=api",
        "name": "Niklas Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/2270/mbox/",
    "series": [
        {
            "id": 561,
            "url": "https://patchwork.libcamera.org/api/series/561/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=561",
            "date": "2019-10-28T02:25:13",
            "name": "libcamera: Rework buffer API",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/561/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/2270/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/2270/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<niklas.soderlund@ragnatech.se>",
        "Received": [
            "from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net\n\t[195.74.38.227])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 50EF36017E\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Oct 2019 03:25:58 +0100 (CET)",
            "from localhost.localdomain (unknown [93.2.121.143])\n\tby bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA\n\tid 43d81398-f92a-11e9-903a-005056917f90;\n\tMon, 28 Oct 2019 03:25:53 +0100 (CET)"
        ],
        "X-Halon-ID": "43d81398-f92a-11e9-903a-005056917f90",
        "Authorized-sender": "niklas@soderlund.pp.se",
        "From": "=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Mon, 28 Oct 2019 03:25:23 +0100",
        "Message-Id": "<20191028022525.796995-11-niklas.soderlund@ragnatech.se>",
        "X-Mailer": "git-send-email 2.23.0",
        "In-Reply-To": "<20191028022525.796995-1-niklas.soderlund@ragnatech.se>",
        "References": "<20191028022525.796995-1-niklas.soderlund@ragnatech.se>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [RFC 10/12] libcamera: buffer: Store buffer\n\tinformation in separate container",
        "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>",
        "X-List-Received-Date": "Mon, 28 Oct 2019 02:25:58 -0000"
    },
    "content": "Use the new BufferInfo container to store information from when a buffer\nis dequeued. This will aid in the ongoing buffer rework and simplify the\ncode.\n\nThis commits breaks the buffer sharing test case as it only deals with\nbuffer information going out of the video device. The next patch will\nrestore the test as it will address the incoming information. All other\ntests as well as cam and qcam works as expected on pipelines not require\nbuffer importing.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n include/libcamera/request.h              |  6 ++-\n src/cam/buffer_writer.cpp                |  5 ++-\n src/cam/buffer_writer.h                  |  4 +-\n src/cam/capture.cpp                      | 21 ++++-----\n src/libcamera/include/pipeline_handler.h |  3 +-\n src/libcamera/include/v4l2_videodevice.h |  4 +-\n src/libcamera/pipeline/ipu3/ipu3.cpp     | 20 ++++-----\n src/libcamera/pipeline/rkisp1/rkisp1.cpp | 40 ++++++++---------\n src/libcamera/pipeline/uvcvideo.cpp      |  6 +--\n src/libcamera/pipeline/vimc.cpp          |  6 +--\n src/libcamera/pipeline_handler.cpp       |  5 ++-\n src/libcamera/request.cpp                |  6 ++-\n src/libcamera/v4l2_videodevice.cpp       | 55 ++++++++----------------\n src/qcam/main_window.cpp                 | 18 ++++----\n src/qcam/main_window.h                   |  2 +-\n test/camera/capture.cpp                  |  4 +-\n test/v4l2_videodevice/buffer_sharing.cpp | 17 ++++----\n test/v4l2_videodevice/capture_async.cpp  |  4 +-\n test/v4l2_videodevice/v4l2_m2mdevice.cpp |  8 ++--\n 19 files changed, 114 insertions(+), 120 deletions(-)",
    "diff": "diff --git a/include/libcamera/request.h b/include/libcamera/request.h\nindex 2d5a5964e99eb75f..88ef7bf03fcfb77b 100644\n--- a/include/libcamera/request.h\n+++ b/include/libcamera/request.h\n@@ -12,12 +12,12 @@\n #include <stdint.h>\n #include <unordered_set>\n \n+#include <libcamera/buffer.h>\n #include <libcamera/controls.h>\n #include <libcamera/signal.h>\n \n namespace libcamera {\n \n-class Buffer;\n class Camera;\n class CameraControlValidator;\n class Stream;\n@@ -39,6 +39,7 @@ public:\n \tControlList &controls() { return *controls_; }\n \tControlList &metadata() { return *metadata_; }\n \tconst std::map<Stream *, Buffer *> &buffers() const { return bufferMap_; }\n+\tconst BufferInfo &info(Buffer *frame) const { return info_.find(frame)->second; };\n \tint addBuffer(std::unique_ptr<Buffer> buffer);\n \tBuffer *findBuffer(Stream *stream) const;\n \n@@ -54,13 +55,14 @@ private:\n \tint prepare();\n \tvoid complete();\n \n-\tbool completeBuffer(Buffer *buffer);\n+\tbool completeBuffer(Buffer *buffer, const BufferInfo &info);\n \n \tCamera *camera_;\n \tCameraControlValidator *validator_;\n \tControlList *controls_;\n \tControlList *metadata_;\n \tstd::map<Stream *, Buffer *> bufferMap_;\n+\tstd::map<Buffer *, BufferInfo> info_;\n \tstd::unordered_set<Buffer *> pending_;\n \n \tconst uint64_t cookie_;\ndiff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp\nindex c33e99c5f8173db8..3ee9e82ba216abb6 100644\n--- a/src/cam/buffer_writer.cpp\n+++ b/src/cam/buffer_writer.cpp\n@@ -21,7 +21,8 @@ BufferWriter::BufferWriter(const std::string &pattern)\n {\n }\n \n-int BufferWriter::write(Buffer *buffer, const std::string &streamName)\n+int BufferWriter::write(Buffer *buffer, const BufferInfo &info,\n+\t\t\tconst std::string &streamName)\n {\n \tstd::string filename;\n \tsize_t pos;\n@@ -32,7 +33,7 @@ int BufferWriter::write(Buffer *buffer, const std::string &streamName)\n \tif (pos != std::string::npos) {\n \t\tstd::stringstream ss;\n \t\tss << streamName << \"-\" << std::setw(6)\n-\t\t   << std::setfill('0') << buffer->sequence();\n+\t\t   << std::setfill('0') << info.sequence();\n \t\tfilename.replace(pos, 1, ss.str());\n \t}\n \ndiff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h\nindex 7bf785d1e83235ff..38f7045c7d4e68a4 100644\n--- a/src/cam/buffer_writer.h\n+++ b/src/cam/buffer_writer.h\n@@ -16,7 +16,9 @@ class BufferWriter\n public:\n \tBufferWriter(const std::string &pattern = \"frame-#.bin\");\n \n-\tint write(libcamera::Buffer *buffer, const std::string &streamName);\n+\tint write(libcamera::Buffer *buffer,\n+\t\t  const libcamera::BufferInfo &info,\n+\t\t  const std::string &streamName);\n \n private:\n \tstd::string pattern_;\ndiff --git a/src/cam/capture.cpp b/src/cam/capture.cpp\nindex e665d819fb777a90..251e9f86c86b508d 100644\n--- a/src/cam/capture.cpp\n+++ b/src/cam/capture.cpp\n@@ -138,32 +138,33 @@ void Capture::requestComplete(Request *request)\n \tif (request->status() == Request::RequestCancelled)\n \t\treturn;\n \n-\tconst std::map<Stream *, Buffer *> &buffers = request->buffers();\n-\n \tstd::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();\n \tdouble fps = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_).count();\n \tfps = last_ != std::chrono::steady_clock::time_point() && fps\n \t    ? 1000.0 / fps : 0.0;\n \tlast_ = now;\n \n-\tstd::stringstream info;\n-\tinfo << \"fps: \" << std::fixed << std::setprecision(2) << fps;\n+\tstd::stringstream infostr;\n+\tinfostr << \"fps: \" << std::fixed << std::setprecision(2) << fps;\n \n+\tconst std::map<Stream *, Buffer *> &buffers = request->buffers();\n \tfor (auto it = buffers.begin(); it != buffers.end(); ++it) {\n \t\tStream *stream = it->first;\n \t\tBuffer *buffer = it->second;\n+\t\tconst BufferInfo &info = request->info(buffer);\n \t\tconst std::string &name = streamName_[stream];\n \n-\t\tinfo << \" \" << name\n-\t\t     << \" (\" << buffer->index() << \")\"\n-\t\t     << \" seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n-\t\t     << \" bytesused: \" << buffer->bytesused();\n+\t\tinfostr << \" \" << name\n+\t\t\t<< \" seq: \" << std::setw(6) << std::setfill('0') << info.sequence();\n+\n+\t\tfor (unsigned int i = 0; i < info.planes(); i++)\n+\t\t\tinfostr << \" bytesused(\" << i << \"): \" << info.plane(i).bytesused;\n \n \t\tif (writer_)\n-\t\t\twriter_->write(buffer, name);\n+\t\t\twriter_->write(buffer, info, name);\n \t}\n \n-\tstd::cout << info.str() << std::endl;\n+\tstd::cout << infostr.str() << std::endl;\n \n \t/*\n \t * Create a new request and populate it with one buffer for each\ndiff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h\nindex 6024357e266c2e2b..e6dbd7687021e4ff 100644\n--- a/src/libcamera/include/pipeline_handler.h\n+++ b/src/libcamera/include/pipeline_handler.h\n@@ -81,7 +81,8 @@ public:\n \n \tvirtual int queueRequest(Camera *camera, Request *request);\n \n-\tbool completeBuffer(Camera *camera, Request *request, Buffer *buffer);\n+\tbool completeBuffer(Camera *camera, Request *request, Buffer *buffer,\n+\t\t\t    const BufferInfo &info);\n \tvoid completeRequest(Camera *camera, Request *request);\n \n \tconst char *name() const { return name_; }\ndiff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\nindex 5b178339d0ce7e2c..01b90ab4654bfba2 100644\n--- a/src/libcamera/include/v4l2_videodevice.h\n+++ b/src/libcamera/include/v4l2_videodevice.h\n@@ -12,6 +12,7 @@\n \n #include <linux/videodev2.h>\n \n+#include <libcamera/buffer.h>\n #include <libcamera/geometry.h>\n #include <libcamera/signal.h>\n \n@@ -166,7 +167,7 @@ public:\n \n \tint queueBuffer(Buffer *buffer);\n \tstd::vector<std::unique_ptr<Buffer>> queueAllBuffers();\n-\tSignal<Buffer *> bufferReady;\n+\tSignal<Buffer *, const BufferInfo &> bufferReady;\n \n \tint streamOn();\n \tint streamOff();\n@@ -194,7 +195,6 @@ private:\n \tint createPlane(BufferMemory *buffer, unsigned int index,\n \t\t\tunsigned int plane, unsigned int length);\n \n-\tBuffer *dequeueBuffer();\n \tvoid bufferAvailable(EventNotifier *notifier);\n \n \tV4L2Capability caps_;\ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 8aa5f34febf16585..01064ac09859155d 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -161,9 +161,9 @@ public:\n \t\tdelete vfStream_;\n \t}\n \n-\tvoid imguOutputBufferReady(Buffer *buffer);\n-\tvoid imguInputBufferReady(Buffer *buffer);\n-\tvoid cio2BufferReady(Buffer *buffer);\n+\tvoid imguOutputBufferReady(Buffer *buffer, const BufferInfo &info);\n+\tvoid imguInputBufferReady(Buffer *buffer, const BufferInfo &info);\n+\tvoid cio2BufferReady(Buffer *buffer, const BufferInfo &info);\n \n \tCIO2Device cio2_;\n \tImgUDevice *imgu_;\n@@ -931,10 +931,10 @@ int PipelineHandlerIPU3::registerCameras()\n  * Buffers completed from the ImgU input are immediately queued back to the\n  * CIO2 unit to continue frame capture.\n  */\n-void IPU3CameraData::imguInputBufferReady(Buffer *buffer)\n+void IPU3CameraData::imguInputBufferReady(Buffer *buffer, const BufferInfo &info)\n {\n \t/* \\todo Handle buffer failures when state is set to BufferError. */\n-\tif (buffer->status() == Buffer::BufferCancelled)\n+\tif (info.status() == BufferInfo::BufferCancelled)\n \t\treturn;\n \n \tcio2_.output_->queueBuffer(buffer);\n@@ -946,15 +946,13 @@ void IPU3CameraData::imguInputBufferReady(Buffer *buffer)\n  *\n  * Buffers completed from the ImgU output are directed to the application.\n  */\n-void IPU3CameraData::imguOutputBufferReady(Buffer *buffer)\n+void IPU3CameraData::imguOutputBufferReady(Buffer *buffer, const BufferInfo &info)\n {\n \tRequest *request = requestFromBuffer(buffer);\n \n-\tif (!pipe_->completeBuffer(camera_, request, buffer))\n-\t\t/* Request not completed yet, return here. */\n+\tif (!pipe_->completeBuffer(camera_, request, buffer, info))\n \t\treturn;\n \n-\t/* Mark the request as complete. */\n \tpipe_->completeRequest(camera_, request);\n }\n \n@@ -965,10 +963,10 @@ void IPU3CameraData::imguOutputBufferReady(Buffer *buffer)\n  * Buffers completed from the CIO2 are immediately queued to the ImgU unit\n  * for further processing.\n  */\n-void IPU3CameraData::cio2BufferReady(Buffer *buffer)\n+void IPU3CameraData::cio2BufferReady(Buffer *buffer, const BufferInfo &info)\n {\n \t/* \\todo Handle buffer failures when state is set to BufferError. */\n-\tif (buffer->status() == Buffer::BufferCancelled)\n+\tif (info.status() == BufferInfo::BufferCancelled)\n \t\treturn;\n \n \timgu_->input_->queueBuffer(buffer);\ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex 0803572754364beb..33a058de18b8cf2e 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -88,7 +88,7 @@ public:\n \t\tsetDelay(QueueBuffers, -1, 10);\n \t}\n \n-\tvoid bufferReady(Buffer *buffer)\n+\tvoid bufferReady(Buffer *buffer, const BufferInfo &info)\n \t{\n \t\t/*\n \t\t * Calculate SOE by taking the end of DMA set by the kernel and applying\n@@ -99,10 +99,10 @@ public:\n \t\tASSERT(frameOffset(SOE) == 0);\n \n \t\tutils::time_point soe = std::chrono::time_point<utils::clock>()\n-\t\t\t+ std::chrono::nanoseconds(buffer->timestamp())\n+\t\t\t+ std::chrono::nanoseconds(info.timestamp())\n \t\t\t+ timeOffset(SOE);\n \n-\t\tnotifyStartOfExposure(buffer->sequence(), soe);\n+\t\tnotifyStartOfExposure(info.sequence(), soe);\n \t}\n \n \tvoid setDelay(unsigned int type, int frame, int msdelay)\n@@ -202,9 +202,9 @@ private:\n \tint initLinks();\n \tint createCamera(MediaEntity *sensor);\n \tvoid tryCompleteRequest(Request *request);\n-\tvoid bufferReady(Buffer *buffer);\n-\tvoid paramReady(Buffer *buffer);\n-\tvoid statReady(Buffer *buffer);\n+\tvoid bufferReady(Buffer *buffer, const BufferInfo &info);\n+\tvoid paramReady(Buffer *buffer, const BufferInfo &info);\n+\tvoid statReady(Buffer *buffer, const BufferInfo &info);\n \n \tMediaDevice *media_;\n \tV4L2Subdevice *dphy_;\n@@ -987,43 +987,43 @@ void PipelineHandlerRkISP1::tryCompleteRequest(Request *request)\n \tdata->frameInfo_.destroy(info->frame);\n }\n \n-void PipelineHandlerRkISP1::bufferReady(Buffer *buffer)\n+void PipelineHandlerRkISP1::bufferReady(Buffer *buffer, const BufferInfo &info)\n {\n \tASSERT(activeCamera_);\n \tRkISP1CameraData *data = cameraData(activeCamera_);\n \tRequest *request = data->requestFromBuffer(buffer);\n \n-\tdata->timeline_.bufferReady(buffer);\n+\tdata->timeline_.bufferReady(buffer, info);\n \n-\tif (data->frame_ <= buffer->sequence())\n-\t\tdata->frame_ = buffer->sequence() + 1;\n+\tif (data->frame_ <= info.sequence())\n+\t\tdata->frame_ = info.sequence() + 1;\n \n-\tcompleteBuffer(activeCamera_, request, buffer);\n+\tcompleteBuffer(activeCamera_, request, buffer, info);\n \ttryCompleteRequest(request);\n }\n \n-void PipelineHandlerRkISP1::paramReady(Buffer *buffer)\n+void PipelineHandlerRkISP1::paramReady(Buffer *buffer, const BufferInfo &info)\n {\n \tASSERT(activeCamera_);\n \tRkISP1CameraData *data = cameraData(activeCamera_);\n \n-\tRkISP1FrameInfo *info = data->frameInfo_.find(buffer);\n+\tRkISP1FrameInfo *rkinfo = data->frameInfo_.find(buffer);\n \n-\tinfo->paramDequeued = true;\n-\ttryCompleteRequest(info->request);\n+\trkinfo->paramDequeued = true;\n+\ttryCompleteRequest(rkinfo->request);\n }\n \n-void PipelineHandlerRkISP1::statReady(Buffer *buffer)\n+void PipelineHandlerRkISP1::statReady(Buffer *buffer, const BufferInfo &info)\n {\n \tASSERT(activeCamera_);\n \tRkISP1CameraData *data = cameraData(activeCamera_);\n \n-\tRkISP1FrameInfo *info = data->frameInfo_.find(buffer);\n-\tif (!info)\n+\tRkISP1FrameInfo *rkinfo = data->frameInfo_.find(buffer);\n+\tif (!rkinfo)\n \t\treturn;\n \n-\tunsigned int frame = info->frame;\n-\tunsigned int statid = RKISP1_STAT_BASE | info->statBuffer->index();\n+\tunsigned int frame = rkinfo->frame;\n+\tunsigned int statid = RKISP1_STAT_BASE | rkinfo->statBuffer->index();\n \n \tIPAOperationData op;\n \top.operation = RKISP1_IPA_EVENT_SIGNAL_STAT_BUFFER;\ndiff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp\nindex 679d82d38227b991..ef2e8c9734f844ce 100644\n--- a/src/libcamera/pipeline/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo.cpp\n@@ -42,7 +42,7 @@ public:\n \t}\n \n \tint init(MediaEntity *entity);\n-\tvoid bufferReady(Buffer *buffer);\n+\tvoid bufferReady(Buffer *buffer, const BufferInfo &info);\n \n \tV4L2VideoDevice *video_;\n \tStream *stream_;\n@@ -373,11 +373,11 @@ int UVCCameraData::init(MediaEntity *entity)\n \treturn 0;\n }\n \n-void UVCCameraData::bufferReady(Buffer *buffer)\n+void UVCCameraData::bufferReady(Buffer *buffer, const BufferInfo &info)\n {\n \tRequest *request = requestFromBuffer(buffer);\n \n-\tpipe_->completeBuffer(camera_, request, buffer);\n+\tpipe_->completeBuffer(camera_, request, buffer, info);\n \tpipe_->completeRequest(camera_, request);\n }\n \ndiff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp\nindex 56898716a8cde074..e3eefc49135179f2 100644\n--- a/src/libcamera/pipeline/vimc.cpp\n+++ b/src/libcamera/pipeline/vimc.cpp\n@@ -56,7 +56,7 @@ public:\n \t}\n \n \tint init(MediaDevice *media);\n-\tvoid bufferReady(Buffer *buffer);\n+\tvoid bufferReady(Buffer *buffer, const BufferInfo &info);\n \n \tCameraSensor *sensor_;\n \tV4L2Subdevice *debayer_;\n@@ -458,11 +458,11 @@ int VimcCameraData::init(MediaDevice *media)\n \treturn 0;\n }\n \n-void VimcCameraData::bufferReady(Buffer *buffer)\n+void VimcCameraData::bufferReady(Buffer *buffer, const BufferInfo &info)\n {\n \tRequest *request = requestFromBuffer(buffer);\n \n-\tpipe_->completeBuffer(camera_, request, buffer);\n+\tpipe_->completeBuffer(camera_, request, buffer, info);\n \tpipe_->completeRequest(camera_, request);\n }\n \ndiff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\nindex d70e286661aded8e..9ce9432449e0e133 100644\n--- a/src/libcamera/pipeline_handler.cpp\n+++ b/src/libcamera/pipeline_handler.cpp\n@@ -393,10 +393,11 @@ int PipelineHandler::queueRequest(Camera *camera, Request *request)\n  * otherwise\n  */\n bool PipelineHandler::completeBuffer(Camera *camera, Request *request,\n-\t\t\t\t     Buffer *buffer)\n+\t\t\t\t     Buffer *buffer, const BufferInfo &info)\n {\n+\tbool ret = request->completeBuffer(buffer, info);\n \tcamera->bufferCompleted.emit(request, buffer);\n-\treturn request->completeBuffer(buffer);\n+\treturn ret;\n }\n \n /**\ndiff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp\nindex a9468ed4b0512a7f..9a0e439a3d05d780 100644\n--- a/src/libcamera/request.cpp\n+++ b/src/libcamera/request.cpp\n@@ -252,12 +252,14 @@ void Request::complete()\n  * \\return True if all buffers contained in the request have completed, false\n  * otherwise\n  */\n-bool Request::completeBuffer(Buffer *buffer)\n+bool Request::completeBuffer(Buffer *buffer, const BufferInfo &info)\n {\n \tint ret = pending_.erase(buffer);\n \tASSERT(ret == 1);\n \n-\tif (buffer->status() == Buffer::BufferCancelled)\n+\tinfo_.emplace(buffer, info);\n+\n+\tif (info.status() == BufferInfo::BufferCancelled)\n \t\tcancelled_ = true;\n \n \treturn !hasPendingBuffers();\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex 8bc2e439e4faeb68..97c6722b8c4c98cf 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -1119,14 +1119,16 @@ std::vector<std::unique_ptr<Buffer>> V4L2VideoDevice::queueAllBuffers()\n }\n \n /**\n- * \\brief Dequeue the next available buffer from the video device\n+ * \\brief Slot to handle completed buffer events from the V4L2 video device\n+ * \\param[in] notifier The event notifier\n  *\n- * This method dequeues the next available buffer from the device. If no buffer\n- * is available to be dequeued it will return nullptr immediately.\n+ * When this slot is called, a Buffer has become available from the device, and\n+ * will be emitted through the bufferReady Signal.\n  *\n- * \\return A pointer to the dequeued buffer on success, or nullptr otherwise\n+ * For Capture video devices the Buffer will contain valid data.\n+ * For Output video devices the Buffer can be considered empty.\n  */\n-Buffer *V4L2VideoDevice::dequeueBuffer()\n+void V4L2VideoDevice::bufferAvailable(EventNotifier *notifier)\n {\n \tstruct v4l2_buffer buf = {};\n \tstruct v4l2_plane planes[VIDEO_MAX_PLANES] = {};\n@@ -1144,10 +1146,10 @@ Buffer *V4L2VideoDevice::dequeueBuffer()\n \tif (ret < 0) {\n \t\tLOG(V4L2, Error)\n \t\t\t<< \"Failed to dequeue buffer: \" << strerror(-ret);\n-\t\treturn nullptr;\n+\t\treturn;\n \t}\n \n-\tASSERT(buf.index < bufferPool_->count());\n+\tLOG(V4L2, Debug) << \"Buffer \" << buf.index << \" is available\";\n \n \tauto it = queuedBuffers_.find(buf.index);\n \tBuffer *buffer = it->second;\n@@ -1156,37 +1158,16 @@ Buffer *V4L2VideoDevice::dequeueBuffer()\n \tif (queuedBuffers_.empty())\n \t\tfdEvent_->setEnabled(false);\n \n-\tbuffer->index_ = buf.index;\n-\tbuffer->bytesused_ = buf.bytesused;\n-\tbuffer->timestamp_ = buf.timestamp.tv_sec * 1000000000ULL\n-\t\t\t   + buf.timestamp.tv_usec * 1000ULL;\n-\tbuffer->sequence_ = buf.sequence;\n-\tbuffer->status_ = buf.flags & V4L2_BUF_FLAG_ERROR\n-\t\t\t? Buffer::BufferError : Buffer::BufferSuccess;\n-\n-\treturn buffer;\n-}\n+\tBufferInfo::Status status = buf.flags & V4L2_BUF_FLAG_ERROR\n+\t\t? BufferInfo::BufferError : BufferInfo::BufferSuccess;\n+\tuint64_t timestamp = buf.timestamp.tv_sec * 1000000000ULL\n+\t\t+ buf.timestamp.tv_usec * 1000ULL;\n \n-/**\n- * \\brief Slot to handle completed buffer events from the V4L2 video device\n- * \\param[in] notifier The event notifier\n- *\n- * When this slot is called, a Buffer has become available from the device, and\n- * will be emitted through the bufferReady Signal.\n- *\n- * For Capture video devices the Buffer will contain valid data.\n- * For Output video devices the Buffer can be considered empty.\n- */\n-void V4L2VideoDevice::bufferAvailable(EventNotifier *notifier)\n-{\n-\tBuffer *buffer = dequeueBuffer();\n-\tif (!buffer)\n-\t\treturn;\n-\n-\tLOG(V4L2, Debug) << \"Buffer \" << buffer->index() << \" is available\";\n+\tBufferInfo info(status, buf.sequence, timestamp, { { buf.bytesused } });\n+\tbuffer->index_ = buf.index;\n \n \t/* Notify anyone listening to the device. */\n-\tbufferReady.emit(buffer);\n+\tbufferReady.emit(buffer, info);\n }\n \n /**\n@@ -1238,9 +1219,11 @@ int V4L2VideoDevice::streamOff()\n \t\tunsigned int index = it.first;\n \t\tBuffer *buffer = it.second;\n \n+\t\tBufferInfo info(BufferInfo::BufferCancelled, 0, 0, { {} });\n+\n \t\tbuffer->index_ = index;\n \t\tbuffer->cancel();\n-\t\tbufferReady.emit(buffer);\n+\t\tbufferReady.emit(buffer, info);\n \t}\n \n \tqueuedBuffers_.clear();\ndiff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp\nindex cca7365ae75687f9..2d7f4ba84fbb6838 100644\n--- a/src/qcam/main_window.cpp\n+++ b/src/qcam/main_window.cpp\n@@ -258,19 +258,19 @@ void MainWindow::requestComplete(Request *request)\n \tframesCaptured_++;\n \n \tBuffer *buffer = buffers.begin()->second;\n+\tconst BufferInfo &info = request->info(buffer);\n \n-\tdouble fps = buffer->timestamp() - lastBufferTime_;\n+\tdouble fps = info.timestamp() - lastBufferTime_;\n \tfps = lastBufferTime_ && fps ? 1000000000.0 / fps : 0.0;\n-\tlastBufferTime_ = buffer->timestamp();\n+\tlastBufferTime_ = info.timestamp();\n \n-\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << buffer->sequence()\n-\t\t  << \" buf: \" << buffer->index()\n-\t\t  << \" bytesused: \" << buffer->bytesused()\n-\t\t  << \" timestamp: \" << buffer->timestamp()\n+\tstd::cout << \"seq: \" << std::setw(6) << std::setfill('0') << info.sequence()\n+\t\t  << \" bytesused: \" << info.plane(0).bytesused\n+\t\t  << \" timestamp: \" << info.timestamp()\n \t\t  << \" fps: \" << std::fixed << std::setprecision(2) << fps\n \t\t  << std::endl;\n \n-\tdisplay(buffer);\n+\tdisplay(buffer, info);\n \n \trequest = camera_->createRequest();\n \tif (!request) {\n@@ -295,7 +295,7 @@ void MainWindow::requestComplete(Request *request)\n \tcamera_->queueRequest(request);\n }\n \n-int MainWindow::display(Buffer *buffer)\n+int MainWindow::display(Buffer *buffer, const BufferInfo &info)\n {\n \tBufferMemory *mem = buffer->mem();\n \tif (mem->planes().size() != 1)\n@@ -303,7 +303,7 @@ int MainWindow::display(Buffer *buffer)\n \n \tPlane &plane = mem->planes().front();\n \tunsigned char *raw = static_cast<unsigned char *>(plane.mem());\n-\tviewfinder_->display(raw, buffer->bytesused());\n+\tviewfinder_->display(raw, info.plane(0).bytesused);\n \n \treturn 0;\n }\ndiff --git a/src/qcam/main_window.h b/src/qcam/main_window.h\nindex 78511581a8d5c025..8cbd72eb0d63cbea 100644\n--- a/src/qcam/main_window.h\n+++ b/src/qcam/main_window.h\n@@ -50,7 +50,7 @@ private:\n \tvoid stopCapture();\n \n \tvoid requestComplete(Request *request);\n-\tint display(Buffer *buffer);\n+\tint display(Buffer *frame, const BufferInfo &info);\n \n \tQString title_;\n \tQTimer titleTimer_;\ndiff --git a/test/camera/capture.cpp b/test/camera/capture.cpp\nindex 83f974749affd3cd..3cf5b798448d01db 100644\n--- a/test/camera/capture.cpp\n+++ b/test/camera/capture.cpp\n@@ -21,7 +21,9 @@ protected:\n \n \tvoid bufferComplete(Request *request, Buffer *buffer)\n \t{\n-\t\tif (buffer->status() != Buffer::BufferSuccess)\n+\t\tconst BufferInfo &info = request->info(buffer);\n+\n+\t\tif (info.status() != BufferInfo::BufferSuccess)\n \t\t\treturn;\n \n \t\tcompleteBuffersCount_++;\ndiff --git a/test/v4l2_videodevice/buffer_sharing.cpp b/test/v4l2_videodevice/buffer_sharing.cpp\nindex 1629f34cfa6c79fe..3609c331cf10e056 100644\n--- a/test/v4l2_videodevice/buffer_sharing.cpp\n+++ b/test/v4l2_videodevice/buffer_sharing.cpp\n@@ -90,24 +90,25 @@ protected:\n \t\treturn 0;\n \t}\n \n-\tvoid captureBufferReady(Buffer *buffer)\n+\tvoid captureBufferReady(Buffer *buffer, const BufferInfo &info)\n \t{\n-\t\tstd::cout << \"Received capture buffer: \" << buffer->index()\n-\t\t\t  << \" sequence \" << buffer->sequence() << std::endl;\n+\t\tstd::cout << \"Received capture buffer  sequence \"\n+\t\t\t  << info.sequence() << std::endl;\n \n-\t\tif (buffer->status() != Buffer::BufferSuccess)\n+\t\tif (info.status() != BufferInfo::BufferSuccess)\n \t\t\treturn;\n \n+\t\tBufferInfo infocopy = info;\n \t\toutput_->queueBuffer(buffer);\n \t\tframesCaptured_++;\n \t}\n \n-\tvoid outputBufferReady(Buffer *buffer)\n+\tvoid outputBufferReady(Buffer *buffer, const BufferInfo &info)\n \t{\n-\t\tstd::cout << \"Received output buffer: \" << buffer->index()\n-\t\t\t  << \" sequence \" << buffer->sequence() << std::endl;\n+\t\tstd::cout << \"Received output buffer sequence \"\n+\t\t\t  << info.sequence() << std::endl;\n \n-\t\tif (buffer->status() != Buffer::BufferSuccess)\n+\t\tif (info.status() != BufferInfo::BufferSuccess)\n \t\t\treturn;\n \n \t\tcapture_->queueBuffer(buffer);\ndiff --git a/test/v4l2_videodevice/capture_async.cpp b/test/v4l2_videodevice/capture_async.cpp\nindex 442a4fe56eace57e..26ea1d17fd901ef8 100644\n--- a/test/v4l2_videodevice/capture_async.cpp\n+++ b/test/v4l2_videodevice/capture_async.cpp\n@@ -20,9 +20,9 @@ public:\n \tCaptureAsyncTest()\n \t\t: V4L2VideoDeviceTest(\"vimc\", \"Raw Capture 0\"), frames(0) {}\n \n-\tvoid receiveBuffer(Buffer *buffer)\n+\tvoid receiveBuffer(Buffer *buffer, const BufferInfo &info)\n \t{\n-\t\tstd::cout << \"Received buffer \" << buffer->index() << std::endl;\n+\t\tstd::cout << \"Received buffer\" << std::endl;\n \t\tframes++;\n \n \t\t/* Requeue the buffer for further use. */\ndiff --git a/test/v4l2_videodevice/v4l2_m2mdevice.cpp b/test/v4l2_videodevice/v4l2_m2mdevice.cpp\nindex 4d3644c2d28792f1..e6ca90a4604dfcda 100644\n--- a/test/v4l2_videodevice/v4l2_m2mdevice.cpp\n+++ b/test/v4l2_videodevice/v4l2_m2mdevice.cpp\n@@ -29,9 +29,9 @@ public:\n \t{\n \t}\n \n-\tvoid outputBufferComplete(Buffer *buffer)\n+\tvoid outputBufferComplete(Buffer *buffer, const BufferInfo &info)\n \t{\n-\t\tcout << \"Received output buffer \" << buffer->index() << endl;\n+\t\tcout << \"Received output buffer\" << endl;\n \n \t\toutputFrames_++;\n \n@@ -39,9 +39,9 @@ public:\n \t\tvim2m_->output()->queueBuffer(buffer);\n \t}\n \n-\tvoid receiveCaptureBuffer(Buffer *buffer)\n+\tvoid receiveCaptureBuffer(Buffer *buffer, const BufferInfo &info)\n \t{\n-\t\tcout << \"Received capture buffer \" << buffer->index() << endl;\n+\t\tcout << \"Received capture buffer\" << endl;\n \n \t\tcaptureFrames_++;\n \n",
    "prefixes": [
        "libcamera-devel",
        "RFC",
        "10/12"
    ]
}