Show a patch.

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

{
    "id": 18962,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/18962/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/18962/",
    "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": "<20230825063707.8734-3-gabbymg94@gmail.com>",
    "date": "2023-08-25T06:37:07",
    "name": "[libcamera-devel,2/2] libcamera: pipeline: uvcvideo: Calculate UVC timestamps",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "a13dae93eee7a773450df2872ae1e318c89af3f1",
    "submitter": {
        "id": 160,
        "url": "https://patchwork.libcamera.org/api/1.1/people/160/?format=api",
        "name": "Gabrielle George",
        "email": "gabbymg94@gmail.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/18962/mbox/",
    "series": [
        {
            "id": 4009,
            "url": "https://patchwork.libcamera.org/api/1.1/series/4009/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4009",
            "date": "2023-08-25T06:37:05",
            "name": "Calculation of new UVC timestamps",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/4009/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/18962/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/18962/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 908AFBF415\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 25 Aug 2023 06:37:33 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id F2A8061E01;\n\tFri, 25 Aug 2023 08:37:32 +0200 (CEST)",
            "from mail-oo1-xc35.google.com (mail-oo1-xc35.google.com\n\t[IPv6:2607:f8b0:4864:20::c35])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AB97F61E01\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 25 Aug 2023 08:37:29 +0200 (CEST)",
            "by mail-oo1-xc35.google.com with SMTP id\n\t006d021491bc7-5733bcf6eb6so372849eaf.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 24 Aug 2023 23:37:29 -0700 (PDT)",
            "from localhost.localdomain (97-115-76-16.ptld.qwest.net.\n\t[97.115.76.16]) by smtp.gmail.com with ESMTPSA id\n\tu41-20020a4a8c2c000000b0056688eea98csm623239ooj.27.2023.08.24.23.37.27\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 24 Aug 2023 23:37:27 -0700 (PDT)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1692945453;\n\tbh=Gz/op4V/CEz9kxR/Pgp31gCIBHQ/CRS0cdt4iLZv7dk=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=vX9LrNVxVHYmvmnu3rTatwoQgDLe2T1pVAaYBcInQNDv/fsoIb1My0ehn3uriciku\n\tLbJ3HfGxmFkNqTO1/CKibTDEoWA59l5PTW20kpU7t06Rh0MdRdLUEX/0C0Vbr3fkwg\n\t4lvq8Ti6sEeEPiMzbSbJlaCGoESK2VcNtfzsxHqsD5H6kwgkfEmxOcKfWKV3h25oSZ\n\tAfM9nKV9g1hfVfMt2T3MkTetUYiG7aBvqu8aMyV/k3VWzKQqMzeEpxMDSyhPQ4p+Bn\n\tvbXljuZo8THgZOCOzjiNFC8QwTRcU32KLk7oDg2l6kUQz+NP2f4NVRqqHbYi+3yIQ2\n\tH/lUsbeK7aAuQ==",
            "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20221208; t=1692945448; x=1693550248;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:to:from:from:to:cc:subject:date:message-id\n\t:reply-to; bh=LjTzj1CqlDJ8g91Ky0tegDwA35QuJF4yES22o5hmF0U=;\n\tb=EBNtYginfgsVHYTc0moNDLh/J578tWaPPzVrNzjKjjRqM9KytCh3vsNC8KRNV9rNc5\n\tBFc4v5g1qm3i0Agc6avpMQfJP/SdnCsoCD30j1vdyW3iax5PaeO3aLxDxTq/7GU5Ki6T\n\tPsrIC6J6y8SyFdNeJ0/MK6i7WVOvx6iqOQcHv9O6pa+TF78XD4r4yNezarq+qCgZjBAn\n\thWKfrVWc4p+ptmi0g+j3jSks+kvCpYFjtz6kJDMmcNsl0YFYYhjlC7lLRF62oRyr9+GM\n\tCjHGYVKX3Gill2fhZR9HZfM7R8qT7tn2aIwojJVQ7a7efoorNMZz0rjOXOEf1oOFsORI\n\t0nIQ=="
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"EBNtYgin\"; dkim-atps=neutral",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20221208; t=1692945448; x=1693550248;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:to:from:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=LjTzj1CqlDJ8g91Ky0tegDwA35QuJF4yES22o5hmF0U=;\n\tb=cbBgjuFPbM5qaEPBhTnTmBsjXqM61KOyKySMe3h792MjH8ARjSTaY0FYqfLi9snQFA\n\tCUJ45gP6AKyYeZiIAE9iPiQufV+TyFlNgd/rsuXU/RAnSNh12dPtnCo8XMwJi1I50BeA\n\tKdonB9fM4iaY1//UOybe2opBUC3MWK7k64nTiOdvuBiwuu9/P5uW1JJk/kTY/C5oCWlc\n\tWTuGW0+7bYRvrdKirFHMMp7HRuo9VLEHxpIFg2KM6Qfw8McjVgbe6qefIMbi7gailQey\n\t1+VZith2sGN2S4fFh/40P1Fa31vRpATTZk/TtbdEdfqWw1C6uTP2A1a0iydJdeb92HDt\n\t5psQ==",
        "X-Gm-Message-State": "AOJu0YxyBHdn4qn0YNEe8PpJ4M6Vx8NI4fPmyhBiSNMnfKfmetlVu29Y\n\tNhmSaVN/9gL3jcCncgj6sbFORtBrO20=",
        "X-Google-Smtp-Source": "AGHT+IHIWmxtcqozip1mPXd43mA+5VRuWOJ/HF12rLxuDthdUcsQW0EWHELh69NgYs6FleMVL0ZmeQ==",
        "X-Received": "by 2002:a4a:92cf:0:b0:573:4e21:5d25 with SMTP id\n\tj15-20020a4a92cf000000b005734e215d25mr16637ooh.9.1692945448053; \n\tThu, 24 Aug 2023 23:37:28 -0700 (PDT)",
        "To": "libcamera-devel@lists.libcamera.org, kieran.bingham@ideasonboard.com,\n\tvedantparanjape160201@gmail.com, gabbymg94@gmail.com",
        "Date": "Thu, 24 Aug 2023 23:37:07 -0700",
        "Message-Id": "<20230825063707.8734-3-gabbymg94@gmail.com>",
        "X-Mailer": "git-send-email 2.34.1",
        "In-Reply-To": "<20230825063707.8734-1-gabbymg94@gmail.com>",
        "References": "<20230825063707.8734-1-gabbymg94@gmail.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH 2/2] libcamera: pipeline: uvcvideo:\n\tCalculate UVC timestamps",
        "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>",
        "From": "Gabby George via libcamera-devel <libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Gabby George <gabbymg94@gmail.com>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Convert the device clock presentation time stamp (pts) to a host\nsystem clock timestamp using the timing data provided by metadata\nbuffers. This is done in two steps.  The first step converts the pts\ninto a usb clock time by linearly interpolating between two points\nwhere both the sof and the device clock time are known.  The second\nstep converts this sof into the host's system clock timestamp by\ninterpolating the sof between two points where both the host timestamp\nand the usb clock timestamp (also known as frame number according to\nthe UVCH field for it).\n\nThese calculations take into account rollover potential of the metadata times.\n\nSigned-off-by: Gabby George <gabbymg94@gmail.com>\n---\n src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 141 ++++++++++++++++++-\n 1 file changed, 137 insertions(+), 4 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\nindex 43ce4f8a..8cc31055 100644\n--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n@@ -914,11 +914,145 @@ void UVCCameraData::endCorruptedStream()\n \t\t<< \"UVC metadata stream corrupted. Reverting to driver timestamps.\";\n }\n \n-unsigned long long calculateTimestamp([[maybe_unused]] const UVCTimestampData &p1,\n+/**\n+ * \\brief Calculate a more accurate host SOF\n+ * \\param[in] sofHost The usb clock time taken by the host\n+ * \\param[in] sofDevice The usb clock time taken by the device\n+ * that has full 11 bit precision.\n+ *\n+ * The precision of the host sof may be lower than the expected 11 bits.\n+ * Obtain a more precise host sof by adding back in the lower 8 bits\n+ * of the difference between the host sof and the more precise device SOF.\n+ *\n+ * \\return An updated usb clock time for the host with 11 bits of precision\n+ */\n+static unsigned short recoverHostSOF(unsigned short sofHost, unsigned short sofDevice)\n+{\n+\tchar sofDelta;\n+\n+\tsofDelta = (sofHost - sofDevice) & 255;\n+\n+\treturn (sofDevice + sofDelta) & 2047;\n+}\n+\n+/**\n+ * \\brief Convert the presentation timestamp recorded by the UVC device to\n+ * a host timestamp.\n+ * \\param[in] p1 Timestamps taken by the usb clock, the device, and the host\n+ * at an early point in time and provided by the UVC driver as metadata\n+ * \\param[in] p2 Timestamps taken by the usb clock, the device, and the host\n+ * taken shortly after the presentation timestamp and provided by the UVC driver\n+ * as metadata\n+ * \\param[in] PTS The presentation time stamp in device time to convert\n+ * to a host timestamp.\n+ *\n+ * The following device to system clock timestamp conversion algorithm is based\n+ * on the Linux kernel's implementation of UVC timestamp calculation.\n+ *\n+ * To convert the presentation time stamp provided by the device to a system\n+ * clock timestamp, first convert the pts to the usb frame number (sof),\n+ * and then from the usb sof to the system timestamp.  The relationship between\n+ * the device clock and the usb clock is linear, as is the relationship between\n+ * the usb clock and the system clock.  To calculate the equations needed for the\n+ * conversion, V4L2 provides a metadata packet with a source timestamp (stc)\n+ * and a usb clock sof taken at the same point in time, as well as a system\n+ * timestamp and a usb clock sof pairing.\n+ *\n+ * Two sets of the timestamp metadata are used to recover this linear relationship\n+ * and convert the pts into system clock time.\n+ *\n+ * \\return The PTS timestamp converted to system clock time.\n+ */\n+unsigned long long calculateTimestamp(const UVCTimestampData &p1,\n \t\t\t\t      const UVCTimestampData &p2,\n-\t\t\t\t      [[maybe_unused]] const unsigned int PTS)\n+\t\t\t\t      const unsigned int PTS)\n {\n-\treturn p2.tsHost;\n+\tunsigned short sof1Device;\n+\tunsigned short sof2Device;\n+\tunsigned int stc1;\n+\tunsigned int stc2;\n+\tunsigned short sof1Host;\n+\tunsigned short sof2Host;\n+\tunsigned int mean;\n+\tunsigned int pts;\n+\tunsigned long long hostTS1;\n+\tunsigned long long hostTS2;\n+\n+\tfloat sof;\n+\tpts = PTS;\n+\n+\t/* Add 2048 to both sof values to prevent underflow */\n+\tsof1Device = p1.sofDevice + 2048;\n+\tstc1 = p1.stcDevice;\n+\tsof2Device = p2.sofDevice + 2048;\n+\tstc2 = p2.stcDevice;\n+\n+\t/* Subtract out the first point's host timestamp for simplicity */\n+\thostTS1 = 0;\n+\thostTS2 = p2.tsHost - p1.tsHost;\n+\n+\t/*\n+\t * Step 1: Convert the pts into an sof usb clock time\n+\t * from p1 and p2's stc and sof time pairs.\n+\t *\n+\t * The equation is:\n+\t * sof = ((sof1 - sof2) *pts + sof1 * stc2 - sof2 * stc1) / ( stc2 - stc1)\n+\t */\n+\n+\t/* If the sof field rolled over, add 2048 so we can extrapolate the line. */\n+\tif (sof2Device < sof1Device) {\n+\t\tsof2Device += 2048;\n+\t}\n+\n+\t/*\n+\t * If the stc value rolled over, subtract half the 32 bit range from the\n+\t * stc and pts values so they fit in the rollover window.\n+\t */\n+\tif (stc2 < stc1) {\n+\t\tstc1 -= (1 << 31);\n+\t\tstc2 -= (1 << 31);\n+\t\tpts -= (1 << 31);\n+\t}\n+\n+\t/* Cast the values or they may overflow at the multiplication step */\n+\tsof = static_cast<float>(\n+\t\t      (static_cast<unsigned long long>((sof2Device - sof1Device)) * static_cast<unsigned long long>(pts)\n+\t\t\t   + static_cast<unsigned long long>(sof1Device) * static_cast<unsigned long long>(stc2) \n+\t\t\t   - static_cast<unsigned long long>(sof2Device) * static_cast<unsigned long long>(stc1))) /\n+\t      static_cast<float>((stc2 - stc1));\n+\n+\t/*\n+\t * Step 2: Similar to Step1, convert the calculated sof\n+\t * to system timestamp from p1 and p2's host timestamp and usb sof pairs\n+\t *\n+\t * The equation is:\n+\t * timestamp = ((ts2 - ts1) * sof + ts1 * sof2 - ts2 * sof1) / (sof2 - sof1)\n+\t */\n+\tsof1Host = recoverHostSOF(p1.sofHost, p1.sofDevice) + 2048;\n+\tsof2Host = recoverHostSOF(p2.sofHost, p2.sofDevice) + 2048;\n+\n+\tif (sof2Host < sof1Host) {\n+\t\tsof2Host += 2048;\n+\t}\n+\n+\t/*\n+\t * This accounts for the possibility that the calculated sof\n+\t * rolled over and the host sof data fields did not.\n+\t */\n+\tmean = (sof1Host + sof2Host) / 2;\n+\n+\tif ((mean - 1024) > sof) {\n+\t\tsof += 2048;\n+\t} else if (sof > mean + 1024) {\n+\t\tsof -= 2048;\n+\t}\n+\n+\t/* note: hostTS 1 has been set to zero so the difference is just the value of hostTS2.*/\n+\tunsigned long long result = static_cast<unsigned long long>(\n+\t\t(hostTS2 * sof + hostTS1 * sof2Host - hostTS2 * sof1Host) / (sof2Host - sof1Host));\n+\n+\t/* Add the subtracted system timestamp from p1 back in */\n+\treturn result + p1.tsHost;\n }\n \n /*\n@@ -943,7 +1077,6 @@ unsigned long long calculateTimestamp([[maybe_unused]] const UVCTimestampData &p\n  */\n void UVCCameraData::bufferReady(FrameBuffer *buffer)\n {\n-\t/* \\todo Use the UVC metadata to calculate a more precise timestamp */\n \tif (!metadata_ || buffer->metadata().sequence < frameStart_) {\n \t\tcompleteRequest(buffer, buffer->metadata().timestamp);\n \t\treturn;\n",
    "prefixes": [
        "libcamera-devel",
        "2/2"
    ]
}