Show a patch.

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

{
    "id": 22214,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/22214/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/22214/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/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": "<20241206142742.7931-4-david.plowman@raspberrypi.com>",
    "date": "2024-12-06T14:27:40",
    "name": "[3/5] libcamera: v4l2: Add wallclock metadata to video devices",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "887af2380e76fbeea80a5d3f88ffa96bd65ff995",
    "submitter": {
        "id": 42,
        "url": "https://patchwork.libcamera.org/api/1.1/people/42/?format=api",
        "name": "David Plowman",
        "email": "david.plowman@raspberrypi.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/22214/mbox/",
    "series": [
        {
            "id": 4856,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4856/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4856",
            "date": "2024-12-06T14:27:37",
            "name": "Implement wallclock timestamps for frames",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4856/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/22214/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/22214/checks/",
    "tags": {},
    "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 E8252BE173\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  6 Dec 2024 14:27:57 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CFC3A6616B;\n\tFri,  6 Dec 2024 15:27:52 +0100 (CET)",
            "from mail-wr1-x435.google.com (mail-wr1-x435.google.com\n\t[IPv6:2a00:1450:4864:20::435])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D6964618B3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  6 Dec 2024 15:27:47 +0100 (CET)",
            "by mail-wr1-x435.google.com with SMTP id\n\tffacd0b85a97d-385e3621518so1580564f8f.1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 06 Dec 2024 06:27:47 -0800 (PST)",
            "from localhost.localdomain ([88.202.252.90])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-386220b071dsm4608219f8f.101.2024.12.06.06.27.46\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tFri, 06 Dec 2024 06:27:46 -0800 (PST)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"qJOVOanT\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1733495267; x=1734100067;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=oAcvVu9/nphoPJeM1gayrL8QAg+lnY0IAKNaVkIKf7A=;\n\tb=qJOVOanTCDD+m8M+e3GDldf3NtTRsNcOXJJxH5vTgInNTbyXakbneTTau0jJQJVXUb\n\t7u0Dc4PZ6PsYnXw5Wx5s9YhYe4dEdEcLd+p3SBhUMHcRTM7yr7J+RU0Cc+iGfaHutTN4\n\t1opTccEOXvaoq2geHaq9lKG4kzoaJedeTONu04nyE3dts8FIKVIGRrJp+Nnds9X7DUVt\n\timrz4u6yBbdXrjxgb/x5WOHnkjF09cUvrAka3qHiwiOYYY+eDuzAd66xlW/chp3iXBQ4\n\tp3LdRkSlGYJyaezQHcD61PkbC7XIWa9lz/qKgvJutylrVQDXWPGhZaakfESlSts86J6h\n\tOxgg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20230601; t=1733495267; x=1734100067;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=oAcvVu9/nphoPJeM1gayrL8QAg+lnY0IAKNaVkIKf7A=;\n\tb=TSx666v22bdnPVydcV5GUX8S1oeunokVFgXQuVmVFTgwYWUdDIqAnDcKlGcpaxSd0O\n\tIvZ8La30isbDdCDQLSyLleNnKmYQRfv5cchP+xXYIE/dk9nLt+kh4GHcm5g8S9GR+EvT\n\tYwxCHDoqEzIEero6bpKehm58LQxZKnhc4hk0XSdnn27HMBIt3vfgwe6qK0kd4zfx9aYq\n\tY+EmtZ9byo2U8uRQNkWjOBPWksR/K0YveExR2h3DcC3+cm+fdlJuDXWDw3DA3drGK2LJ\n\tWczD5pk6SeXH12DCZIASE0EvXm+jeQQime4fo7HZFBrRYDklRyG+hk85kvrscLiXPwkz\n\toPhA==",
        "X-Gm-Message-State": "AOJu0Yzc+IRPKUiBPgfESQbfWckNYfvqKPPRH8Rv4GaP2mzGkBbtP/wU\n\tqko8jZ0at3UrO4EkEYzWX5vDnfz2jJZKq+e6dWd9AfWxGw9e5V8Cw/NtEe+al8vow/ZZrPQGP8E\n\tf",
        "X-Gm-Gg": "ASbGnct/WZ1rn9yEK2AOlxmqHOvzbnLsha3jV1xQ0nxPMC87dpPmb0ljofnTOZoFELv\n\t93uOTSz3lZSu2d8p9R3bZl3qW6ef1atduvzj1aCFg9YHqGD7rnXweajMg1Ahzeax483HJm7SyIF\n\tZK8anipuum03CxTDQueYP7c3JB6m1+O6UBObtx6qI7oE0HBg6ey7KOFUYlbkW+FVgwlH4IgEVnt\n\td7zrB8HHRZdvnI/Hh1Ea2rip9HLNQtg+JW2P7gPGoMHEL1IYsmG+XrRcGOVxUmzmxIY5JAF5GU=",
        "X-Google-Smtp-Source": "AGHT+IFRtD17/etU97O2m2ykLDQVmAa7qfsAw76noXUeAIF4ce7P+5BSMmzss4DB32GAfb9qYcfHMQ==",
        "X-Received": "by 2002:a05:6000:717:b0:385:f4b0:596 with SMTP id\n\tffacd0b85a97d-3862b3632ecmr2536499f8f.18.1733495267051; \n\tFri, 06 Dec 2024 06:27:47 -0800 (PST)",
        "From": "David Plowman <david.plowman@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "David Plowman <david.plowman@raspberrypi.com>",
        "Subject": "[PATCH 3/5] libcamera: v4l2: Add wallclock metadata to video devices",
        "Date": "Fri,  6 Dec 2024 14:27:40 +0000",
        "Message-Id": "<20241206142742.7931-4-david.plowman@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.39.5",
        "In-Reply-To": "<20241206142742.7931-1-david.plowman@raspberrypi.com>",
        "References": "<20241206142742.7931-1-david.plowman@raspberrypi.com>",
        "MIME-Version": "1.0",
        "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>"
    },
    "content": "FrameMetadata is extended to include a wallclock timestamp.\n\nWhen a frame is dequeued, we use the ClockRecovery class to generate a\ngood estimate of a wallclock timestamp to correspond to the frame's\nSensorTimestamp.\n\nPipeline handlers must enable wallclocks for chosen devices by passing\nan appropriate ClockRecovery object.\n\nSigned-off-by: David Plowman <david.plowman@raspberrypi.com>\n---\n include/libcamera/framebuffer.h               |  1 +\n include/libcamera/internal/v4l2_videodevice.h |  5 +++\n src/libcamera/v4l2_videodevice.cpp            | 36 ++++++++++++++++++-\n 3 files changed, 41 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/include/libcamera/framebuffer.h b/include/libcamera/framebuffer.h\nindex ff839243..4579d0c6 100644\n--- a/include/libcamera/framebuffer.h\n+++ b/include/libcamera/framebuffer.h\n@@ -35,6 +35,7 @@ struct FrameMetadata {\n \tStatus status;\n \tunsigned int sequence;\n \tuint64_t timestamp;\n+\tuint64_t wallClock;\n \n \tSpan<Plane> planes() { return planes_; }\n \tSpan<const Plane> planes() const { return planes_; }\ndiff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h\nindex f021c2a0..5327c112 100644\n--- a/include/libcamera/internal/v4l2_videodevice.h\n+++ b/include/libcamera/internal/v4l2_videodevice.h\n@@ -37,6 +37,7 @@\n \n namespace libcamera {\n \n+class ClockRecovery;\n class EventNotifier;\n class MediaDevice;\n class MediaEntity;\n@@ -232,6 +233,8 @@ public:\n \n \tV4L2PixelFormat toV4L2PixelFormat(const PixelFormat &pixelFormat) const;\n \n+\tvoid enableWallClock(ClockRecovery *wallClockRecovery);\n+\n protected:\n \tstd::string logPrefix() const override;\n \n@@ -290,6 +293,8 @@ private:\n \n \tTimer watchdog_;\n \tutils::Duration watchdogDuration_;\n+\n+\tClockRecovery *wallClockRecovery_;\n };\n \n class V4L2M2MDevice\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex a5cf6784..2007dffc 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -26,6 +26,7 @@\n #include <libcamera/base/unique_fd.h>\n #include <libcamera/base/utils.h>\n \n+#include \"libcamera/internal/clock_recovery.h\"\n #include \"libcamera/internal/formats.h\"\n #include \"libcamera/internal/framebuffer.h\"\n #include \"libcamera/internal/media_device.h\"\n@@ -534,7 +535,7 @@ std::ostream &operator<<(std::ostream &out, const V4L2DeviceFormat &f)\n V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)\n \t: V4L2Device(deviceNode), formatInfo_(nullptr), cache_(nullptr),\n \t  fdBufferNotifier_(nullptr), state_(State::Stopped),\n-\t  watchdogDuration_(0.0)\n+\t  watchdogDuration_(0.0), wallClockRecovery_(nullptr)\n {\n \t/*\n \t * We default to an MMAP based CAPTURE video device, however this will\n@@ -1865,6 +1866,17 @@ FrameBuffer *V4L2VideoDevice::dequeueBuffer()\n \tmetadata.timestamp = buf.timestamp.tv_sec * 1000000000ULL\n \t\t\t   + buf.timestamp.tv_usec * 1000ULL;\n \n+\tmetadata.wallClock = 0;\n+\tif (wallClockRecovery_) {\n+\t\t/*\n+\t\t * Sample the internal (CLOCK_BOOTTIME) and realtime (CLOCK_REALTIME) clocks and\n+\t\t * update the clock recovery model. Then derive the wallclock estimate for the\n+\t\t * frame timestamp.\n+\t\t */\n+\t\twallClockRecovery_->addSample();\n+\t\tmetadata.wallClock = wallClockRecovery_->getOutput(metadata.timestamp / 1000);\n+\t}\n+\n \tif (V4L2_TYPE_IS_OUTPUT(buf.type))\n \t\treturn buffer;\n \n@@ -1965,6 +1977,11 @@ int V4L2VideoDevice::streamOn()\n \t\treturn ret;\n \t}\n \n+\tif (wallClockRecovery_) {\n+\t\t/* A good moment to sample the clocks to improve the clock recovery model. */\n+\t\twallClockRecovery_->addSample();\n+\t}\n+\n \tstate_ = State::Streaming;\n \tif (watchdogDuration_ && !queuedBuffers_.empty())\n \t\twatchdog_.start(std::chrono::duration_cast<std::chrono::milliseconds>(watchdogDuration_));\n@@ -2120,6 +2137,23 @@ V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelForma\n \treturn {};\n }\n \n+/**\n+ * \\brief Enable wall clock timestamps for this device\n+ * \\param[in] wallClockRecovery an appropriately configured ClockRecovery, or\n+ * nullptr to disable wall clocks\n+ *\n+ * When buffers are dequeued, wall clock timestamps will be generated that\n+ * correspond to the frame's timestamp, as returned by V4l2.\n+ */\n+void V4L2VideoDevice::enableWallClock(ClockRecovery *wallClockRecovery)\n+{\n+\twallClockRecovery_ = wallClockRecovery;\n+\n+\t/* Also a reasonable moment to sample the two clocks. */\n+\tif (wallClockRecovery_)\n+\t\twallClockRecovery_->addSample();\n+}\n+\n /**\n  * \\class V4L2M2MDevice\n  * \\brief Memory-to-Memory video device\n",
    "prefixes": [
        "3/5"
    ]
}