Show a patch.

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

{
    "id": 907,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/907/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/907/",
    "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": "<20190403150735.27580-3-jacopo@jmondi.org>",
    "date": "2019-04-03T15:07:29",
    "name": "[libcamera-devel,v3,2/8] libcamera: ipu3: Create camera with 2 streams",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "309fb3c9e32936a1297bfd33bd1974748865edd1",
    "submitter": {
        "id": 3,
        "url": "https://patchwork.libcamera.org/api/1.1/people/3/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo@jmondi.org"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/907/mbox/",
    "series": [
        {
            "id": 239,
            "url": "https://patchwork.libcamera.org/api/1.1/series/239/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=239",
            "date": "2019-04-03T15:07:27",
            "name": "libcamera: ipu3: Multiple streams support",
            "version": 3,
            "mbox": "https://patchwork.libcamera.org/series/239/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/907/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/907/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<jacopo@jmondi.org>",
        "Received": [
            "from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net\n\t[217.70.183.199])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id B8061610C5\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 17:06:56 +0200 (CEST)",
            "from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 4F1D7FF806;\n\tWed,  3 Apr 2019 15:06:56 +0000 (UTC)"
        ],
        "X-Originating-IP": "2.224.242.101",
        "From": "Jacopo Mondi <jacopo@jmondi.org>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Wed,  3 Apr 2019 17:07:29 +0200",
        "Message-Id": "<20190403150735.27580-3-jacopo@jmondi.org>",
        "X-Mailer": "git-send-email 2.21.0",
        "In-Reply-To": "<20190403150735.27580-1-jacopo@jmondi.org>",
        "References": "<20190403150735.27580-1-jacopo@jmondi.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v3 2/8] libcamera: ipu3: Create camera\n\twith 2 streams",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.23",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "X-List-Received-Date": "Wed, 03 Apr 2019 15:06:57 -0000"
    },
    "content": "Create each IPU3 camera with two streams: 'output' and 'viewfinder'\nwhich represents the video stream from main and secondary ImgU output\nrespectively.\n\nRe-work stream configuration to handle the two video streams 'output'\nand 'viewfinder' separately.\n\nAs the IPU3 driver requires viewfinder and stat video nodes to be\nstarted not to stall ImgU processing, keep track of which streams have\nbeen requested by the application, and configure 'output', 'viewfinder'\nand 'stat' regardless of the user requests.\n\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n src/libcamera/pipeline/ipu3/ipu3.cpp | 216 +++++++++++++++++++++------\n 1 file changed, 170 insertions(+), 46 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 164e187c769d..caf1051c58ab 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -171,17 +171,61 @@ private:\n \t\tCIO2Device cio2_;\n \t\tImgUDevice *imgu_;\n \n-\t\tStream stream_;\n+\t\tStream outStream_;\n+\t\tStream vfStream_;\n+\n+\t\tunsigned int activeStreamsMask;\n \t};\n \n \tstatic constexpr unsigned int IPU3_BUFFER_COUNT = 4;\n \n+\tstatic constexpr unsigned int IPU3_STREAM_OUTPUT = BIT(0);\n+\tstatic constexpr unsigned int IPU3_STREAM_VF = BIT(1);\n+\n \tIPU3CameraData *cameraData(const Camera *camera)\n \t{\n \t\treturn static_cast<IPU3CameraData *>(\n \t\t\tPipelineHandler::cameraData(camera));\n \t}\n \n+\tbool isOutput(IPU3CameraData *data, Stream *stream)\n+\t{\n+\t\treturn &data->outStream_ == stream;\n+\t}\n+\tbool isOutputActive(IPU3CameraData *data)\n+\t{\n+\t\treturn (data->activeStreamsMask & IPU3_STREAM_OUTPUT) ?\n+\t\t\ttrue : false;\n+\t}\n+\tvoid setOutputActive(IPU3CameraData *data)\n+\t{\n+\t\tdata->activeStreamsMask |= IPU3_STREAM_OUTPUT;\n+\t}\n+\tbool isViewfinder(IPU3CameraData *data, Stream *stream)\n+\t{\n+\t\treturn &data->vfStream_ == stream;\n+\t}\n+\tbool isViewfinderActive(IPU3CameraData *data)\n+\t{\n+\t\treturn (data->activeStreamsMask & IPU3_STREAM_VF) ?\n+\t\t\ttrue : false;\n+\t}\n+\tvoid setViewfinderActive(IPU3CameraData *data)\n+\t{\n+\t\tdata->activeStreamsMask |= IPU3_STREAM_VF;\n+\t}\n+\tbool isStreamActive(IPU3CameraData *data, Stream *stream)\n+\t{\n+\t\tif (isOutput(data, stream) &&\n+\t\t    isOutputActive(data))\n+\t\t\treturn true;\n+\t\tif (isViewfinder(data, stream) &&\n+\t\t    isViewfinderActive(data))\n+\t\t\treturn true;\n+\n+\t\treturn false;\n+\t}\n+\n \tint registerCameras();\n \n \tImgUDevice imgu0_;\n@@ -210,7 +254,7 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera,\n {\n \tstd::map<Stream *, StreamConfiguration> configs;\n \tIPU3CameraData *data = cameraData(camera);\n-\tStreamConfiguration *config = &configs[&data->stream_];\n+\tStreamConfiguration config = {};\n \n \t/*\n \t * FIXME: Soraka: the maximum resolution reported by both sensors\n@@ -220,52 +264,93 @@ PipelineHandlerIPU3::streamConfiguration(Camera *camera,\n \t *\n \t * \\todo Clarify ImgU alignement requirements.\n \t */\n-\tconfig->width = 2560;\n-\tconfig->height = 1920;\n-\tconfig->pixelFormat = V4L2_PIX_FMT_NV12;\n-\tconfig->bufferCount = IPU3_BUFFER_COUNT;\n+\tconfig.width = 2560;\n+\tconfig.height = 1920;\n+\tconfig.pixelFormat = V4L2_PIX_FMT_NV12;\n+\tconfig.bufferCount = IPU3_BUFFER_COUNT;\n+\n+\tconfigs[&data->outStream_] = config;\n+\tLOG(IPU3, Debug)\n+\t\t<< \"Stream 'output' format set to \" << config.width << \"x\"\n+\t\t<< config.height << \"-0x\" << std::hex << std::setfill('0')\n+\t\t<< std::setw(8) << config.pixelFormat;\n \n+\tconfigs[&data->vfStream_] = config;\n \tLOG(IPU3, Debug)\n-\t\t<< \"Stream format set to \" << config->width << \"x\"\n-\t\t<< config->height << \"-0x\" << std::hex << std::setfill('0')\n-\t\t<< std::setw(8) << config->pixelFormat;\n+\t\t<< \"Stream 'viewfinder' format set to \" << config.width << \"x\"\n+\t\t<< config.height << \"-0x\" << std::hex << std::setfill('0')\n+\t\t<< std::setw(8) << config.pixelFormat;\n \n \treturn configs;\n }\n \n int PipelineHandlerIPU3::configureStreams(Camera *camera,\n-\t\t\t\t\t  std::map<Stream *, StreamConfiguration> &config)\n+\t\t\t\t\t  std::map<Stream *,\n+\t\t\t\t\t\t   StreamConfiguration> &config)\n {\n \tIPU3CameraData *data = cameraData(camera);\n-\tconst StreamConfiguration &cfg = config[&data->stream_];\n+\tStreamConfiguration CIO2Config = {};\n \tCIO2Device *cio2 = &data->cio2_;\n \tImgUDevice *imgu = data->imgu_;\n \tint ret;\n \n-\tLOG(IPU3, Info)\n-\t\t<< \"Requested image format \" << cfg.width << \"x\"\n-\t\t<< cfg.height << \"-0x\" << std::hex << std::setfill('0')\n-\t\t<< std::setw(8) << cfg.pixelFormat << \" on camera '\"\n-\t\t<< camera->name() << \"'\";\n+\t/* Remove previously configured stream masks to store the new ones. */\n+\tdata->activeStreamsMask = 0;\n+\tfor (auto const &streamConfig : config) {\n+\t\tStream *stream = streamConfig.first;\n+\t\tconst StreamConfiguration &cfg = streamConfig.second;\n \n-\t/*\n-\t * Verify that the requested size respects the IPU3 alignement\n-\t * requirements (the image width shall be a multiple of 8 pixels and\n-\t * its height a multiple of 4 pixels) and the camera maximum sizes.\n-\t *\n-\t * \\todo: consider the BDS scaling factor requirements:\n-\t * \"the downscaling factor must be an integer value multiple of 1/32\"\n-\t */\n-\tif (cfg.width % 8 || cfg.height % 4) {\n-\t\tLOG(IPU3, Error) << \"Invalid stream size: bad alignment\";\n-\t\treturn -EINVAL;\n-\t}\n+\t\t/*\n+\t\t * Verify that the requested size respects the IPU3 alignement\n+\t\t * requirements (the image width shall be a multiple of 8\n+\t\t * pixels and its height a multiple of 4 pixels) and the camera\n+\t\t * maximum sizes.\n+\t\t *\n+\t\t * \\todo: consider the BDS scaling factor requirements: \"the\n+\t\t * downscaling factor must be an integer value multiple of\n+\t\t * 1/32\"\n+\t\t */\n+\t\tif (cfg.width % 8 || cfg.height % 4) {\n+\t\t\tLOG(IPU3, Error)\n+\t\t\t\t<< \"Invalid stream size: bad alignment\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n \n-\tif (cfg.width > cio2->maxSize_.width ||\n-\t    cfg.height > cio2->maxSize_.height) {\n-\t\tLOG(IPU3, Error)\n-\t\t\t<< \"Invalid stream size: larger than sensor resolution\";\n-\t\treturn -EINVAL;\n+\t\tif (cfg.width > cio2->maxSize_.width ||\n+\t\t    cfg.height > cio2->maxSize_.height) {\n+\t\t\tLOG(IPU3, Error)\n+\t\t\t\t<< \"Invalid stream size: larger than sensor resolution\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tLOG(IPU3, Info)\n+\t\t\t<< \"Requested image format \" << cfg.width << \"x\"\n+\t\t\t<< cfg.height << \"-0x\" << std::hex << std::setw(8)\n+\t\t\t<< cfg.pixelFormat << \" on camera'\"\n+\t\t\t<< camera->name() << \"'\";\n+\n+\t\t/*\n+\t\t * FIXME: As viewfinder should be operated even when\n+\t\t * applications do not intend to use it, we need to keep track\n+\t\t * of which streams have to be configured, to make meaningful\n+\t\t * decisions at configure and request queueing time.\n+\t\t *\n+\t\t * Walk here all the streams to configure and collect the\n+\t\t * active ones in a bitmaks.\n+\t\t */\n+\t\tif (isOutput(data, stream))\n+\t\t\tsetOutputActive(data);\n+\t\tif (isViewfinder(data, stream))\n+\t\t\tsetViewfinderActive(data);\n+\n+\t\t/*\n+\t\t * Collect the maximum width and height: IPU3 can downscale\n+\t\t * only.\n+\t\t */\n+\t\tif (cfg.width > CIO2Config.width)\n+\t\t\tCIO2Config.width = cfg.width;\n+\t\tif (cfg.height > CIO2Config.height)\n+\t\t\tCIO2Config.height = cfg.height;\n \t}\n \n \t/*\n@@ -281,26 +366,62 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera,\n \t * adjusted format to be propagated to the ImgU output devices.\n \t */\n \tV4L2DeviceFormat cio2Format = {};\n-\tret = cio2->configure(cfg, &cio2Format);\n+\tret = cio2->configure(CIO2Config, &cio2Format);\n \tif (ret)\n \t\treturn ret;\n \n-\tret = imgu->configureInput(cfg, &cio2Format);\n+\tret = imgu->configureInput(CIO2Config, &cio2Format);\n \tif (ret)\n \t\treturn ret;\n \n \t/* Apply the format to the ImgU output, viewfinder and stat. */\n-\tret = imgu->configureOutput(&imgu->output_, cfg);\n-\tif (ret)\n-\t\treturn ret;\n+\tfor (auto const &streamConfig : config) {\n+\t\tStream *stream = streamConfig.first;\n+\t\tconst StreamConfiguration &cfg = streamConfig.second;\n \n-\tret = imgu->configureOutput(&imgu->viewfinder_, cfg);\n-\tif (ret)\n-\t\treturn ret;\n+\t\tif (isOutput(data, stream)) {\n+\t\t\tret = imgu->configureOutput(&imgu->output_, cfg);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n \n-\tret = imgu->configureOutput(&imgu->stat_, cfg);\n-\tif (ret)\n-\t\treturn ret;\n+\t\t\tret = imgu->configureOutput(&imgu->stat_, cfg);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\n+\n+\t\t\tif (isViewfinderActive(data))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * Configure viewfinder using the output stream\n+\t\t\t * configuration if it is not part of the active\n+\t\t\t * streams list.\n+\t\t\t */\n+\t\t\tret = imgu->configureOutput(&imgu->viewfinder_, cfg);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t} else if (isViewfinder(data, stream)) {\n+\t\t\tret = imgu->configureOutput(&imgu->viewfinder_, cfg);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\n+\t\t\tif (isOutputActive(data))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * Configure output using the viewfinder stream\n+\t\t\t * configuration if it is not part of the active\n+\t\t\t * streams list.\n+\t\t\t */\n+\t\t\tret = imgu->configureOutput(&imgu->output_, cfg);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\n+\t\t\tret = imgu->configureOutput(&imgu->stat_, cfg);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t}\n \n \treturn 0;\n }\n@@ -404,7 +525,7 @@ int PipelineHandlerIPU3::queueRequest(Camera *camera, Request *request)\n {\n \tIPU3CameraData *data = cameraData(camera);\n \tV4L2Device *output = data->imgu_->output_.dev;\n-\tStream *stream = &data->stream_;\n+\tStream *stream = &data->outStream_;\n \n \t/* Queue a buffer to the ImgU output for capture. */\n \tBuffer *buffer = request->findBuffer(stream);\n@@ -554,7 +675,10 @@ int PipelineHandlerIPU3::registerCameras()\n \tfor (unsigned int id = 0; id < 4 && numCameras < 2; ++id) {\n \t\tstd::unique_ptr<IPU3CameraData> data =\n \t\t\tutils::make_unique<IPU3CameraData>(this);\n-\t\tstd::set<Stream *> streams{ &data->stream_ };\n+\t\tstd::set<Stream *> streams = {\n+\t\t\t&data->outStream_,\n+\t\t\t&data->vfStream_,\n+\t\t};\n \t\tCIO2Device *cio2 = &data->cio2_;\n \n \t\tret = cio2->init(cio2MediaDev_.get(), id);\n",
    "prefixes": [
        "libcamera-devel",
        "v3",
        "2/8"
    ]
}