Patch Detail
Show a patch.
GET /api/1.1/patches/3662/?format=api
{ "id": 3662, "url": "https://patchwork.libcamera.org/api/1.1/patches/3662/?format=api", "web_url": "https://patchwork.libcamera.org/patch/3662/", "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": "<20200502121356.1045727-2-niklas.soderlund@ragnatech.se>", "date": "2020-05-02T12:13:54", "name": "[libcamera-devel,v4,1/3] qcam: Allow for a second raw stream to be configured", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "9660f418d065a3a079b1fa4726a948f25cb5fe89", "submitter": { "id": 5, "url": "https://patchwork.libcamera.org/api/1.1/people/5/?format=api", "name": "Niklas Söderlund", "email": "niklas.soderlund@ragnatech.se" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/3662/mbox/", "series": [ { "id": 870, "url": "https://patchwork.libcamera.org/api/1.1/series/870/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=870", "date": "2020-05-02T12:13:53", "name": "qcam: Add RAW capture support", "version": 4, "mbox": "https://patchwork.libcamera.org/series/870/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/3662/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/3662/checks/", "tags": {}, "headers": { "Return-Path": "<niklas.soderlund@ragnatech.se>", "Received": [ "from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net\n\t[195.74.38.228])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4FED9603F4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 2 May 2020 14:14:05 +0200 (CEST)", "from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de\n\t[79.202.35.146]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA\n\tid 681024e0-8c6e-11ea-89d0-0050569116f7;\n\tSat, 02 May 2020 14:14:01 +0200 (CEST)" ], "X-Halon-ID": "681024e0-8c6e-11ea-89d0-0050569116f7", "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": "Sat, 2 May 2020 14:13:54 +0200", "Message-Id": "<20200502121356.1045727-2-niklas.soderlund@ragnatech.se>", "X-Mailer": "git-send-email 2.26.2", "In-Reply-To": "<20200502121356.1045727-1-niklas.soderlund@ragnatech.se>", "References": "<20200502121356.1045727-1-niklas.soderlund@ragnatech.se>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v4 1/3] qcam: Allow for a second raw\n\tstream to be configured", "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": "Sat, 02 May 2020 12:14:05 -0000" }, "content": "Allow a second stream to be configured for raw capture. This change only\nadds support for configuring and allocating buffers for the second\nstream. Later changes are needed to queue the allocated buffers to the\ncamera when the user wishes to capture a raw frame.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n* Changes since v1\n- Keep doneQueue_ as a QQueue and keep the original processing\n granularity.\n\n* Changes since v2\n- Update a comment.\n---\n src/qcam/main_window.cpp | 110 ++++++++++++++++++++++++++-------------\n src/qcam/main_window.h | 8 ++-\n 2 files changed, 79 insertions(+), 39 deletions(-)", "diff": "diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp\nindex b9348111dfa28914..0bd9f3583ea4f6d4 100644\n--- a/src/qcam/main_window.cpp\n+++ b/src/qcam/main_window.cpp\n@@ -281,17 +281,30 @@ void MainWindow::toggleCapture(bool start)\n int MainWindow::startCapture()\n {\n \tStreamRoles roles = StreamKeyValueParser::roles(options_[OptStream]);\n+\tstd::vector<Request *> requests;\n \tint ret;\n \n \t/* Verify roles are supported. */\n-\tif (roles.size() != 1) {\n-\t\tqCritical() << \"Only one stream supported\";\n-\t\treturn -EINVAL;\n-\t}\n-\n-\tif (roles[0] != StreamRole::Viewfinder) {\n-\t\tqCritical() << \"Only viewfinder supported\";\n-\t\treturn -EINVAL;\n+\tswitch (roles.size()) {\n+\tcase 1:\n+\t\tif (roles[0] != StreamRole::Viewfinder) {\n+\t\t\tqWarning() << \"Only viewfinder supported for single stream\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tbreak;\n+\tcase 2:\n+\t\tif (roles[0] != StreamRole::Viewfinder ||\n+\t\t roles[1] != StreamRole::StillCaptureRaw) {\n+\t\t\tqWarning() << \"Only viewfinder + raw supported for dual streams\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tif (roles.size() != 1) {\n+\t\t\tqWarning() << \"Unsuported stream configuration\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tbreak;\n \t}\n \n \t/* Configure the camera. */\n@@ -301,17 +314,17 @@ int MainWindow::startCapture()\n \t\treturn -EINVAL;\n \t}\n \n-\tStreamConfiguration &cfg = config_->at(0);\n+\tStreamConfiguration &vfConfig = config_->at(0);\n \n \t/* Use a format supported by the viewfinder if available. */\n-\tstd::vector<PixelFormat> formats = cfg.formats().pixelformats();\n+\tstd::vector<PixelFormat> formats = vfConfig.formats().pixelformats();\n \tfor (const PixelFormat &format : viewfinder_->nativeFormats()) {\n \t\tauto match = std::find_if(formats.begin(), formats.end(),\n \t\t\t\t\t [&](const PixelFormat &f) {\n \t\t\t\t\t\t return f == format;\n \t\t\t\t\t });\n \t\tif (match != formats.end()) {\n-\t\t\tcfg.pixelFormat = format;\n+\t\t\tvfConfig.pixelFormat = format;\n \t\t\tbreak;\n \t\t}\n \t}\n@@ -331,7 +344,7 @@ int MainWindow::startCapture()\n \n \tif (validation == CameraConfiguration::Adjusted)\n \t\tqInfo() << \"Stream configuration adjusted to \"\n-\t\t\t<< cfg.toString().c_str();\n+\t\t\t<< vfConfig.toString().c_str();\n \n \tret = camera_->configure(config_.get());\n \tif (ret < 0) {\n@@ -339,10 +352,16 @@ int MainWindow::startCapture()\n \t\treturn ret;\n \t}\n \n+\t/* Store stream allocation. */\n+\tvfStream_ = config_->at(0).stream();\n+\tif (config_->size() == 2)\n+\t\trawStream_ = config_->at(1).stream();\n+\telse\n+\t\trawStream_ = nullptr;\n+\n \t/* Configure the viewfinder. */\n-\tStream *stream = cfg.stream();\n-\tret = viewfinder_->setFormat(cfg.pixelFormat,\n-\t\t\t\t QSize(cfg.size.width, cfg.size.height));\n+\tret = viewfinder_->setFormat(vfConfig.pixelFormat,\n+\t\t\t\t QSize(vfConfig.size.width, vfConfig.size.height));\n \tif (ret < 0) {\n \t\tqInfo() << \"Failed to set viewfinder format\";\n \t\treturn ret;\n@@ -350,16 +369,33 @@ int MainWindow::startCapture()\n \n \tadjustSize();\n \n-\t/* Allocate buffers and requests. */\n+\t/* Allocate and map buffers. */\n \tallocator_ = new FrameBufferAllocator(camera_);\n-\tret = allocator_->allocate(stream);\n-\tif (ret < 0) {\n-\t\tqWarning() << \"Failed to allocate capture buffers\";\n-\t\treturn ret;\n+\tfor (StreamConfiguration &config : *config_) {\n+\t\tStream *stream = config.stream();\n+\n+\t\tret = allocator_->allocate(stream);\n+\t\tif (ret < 0) {\n+\t\t\tqWarning() << \"Failed to allocate capture buffers\";\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tfor (const std::unique_ptr<FrameBuffer> &buffer : allocator_->buffers(stream)) {\n+\t\t\t/* Map memory buffers and cache the mappings. */\n+\t\t\tconst FrameBuffer::Plane &plane = buffer->planes().front();\n+\t\t\tvoid *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED,\n+\t\t\t\t\t plane.fd.fd(), 0);\n+\t\t\tmappedBuffers_[buffer.get()] = { memory, plane.length };\n+\n+\t\t\t/* Store buffers on the free list. */\n+\t\t\tfreeBuffers_[stream].enqueue(buffer.get());\n+\t\t}\n \t}\n \n-\tstd::vector<Request *> requests;\n-\tfor (const std::unique_ptr<FrameBuffer> &buffer : allocator_->buffers(stream)) {\n+\t/* Create requests and fill them with buffers from the viewfinder. */\n+\twhile (!freeBuffers_[vfStream_].isEmpty()) {\n+\t\tFrameBuffer *buffer = freeBuffers_[vfStream_].dequeue();\n+\n \t\tRequest *request = camera_->createRequest();\n \t\tif (!request) {\n \t\t\tqWarning() << \"Can't create request\";\n@@ -367,19 +403,13 @@ int MainWindow::startCapture()\n \t\t\tgoto error;\n \t\t}\n \n-\t\tret = request->addBuffer(stream, buffer.get());\n+\t\tret = request->addBuffer(vfStream_, buffer);\n \t\tif (ret < 0) {\n \t\t\tqWarning() << \"Can't set buffer for request\";\n \t\t\tgoto error;\n \t\t}\n \n \t\trequests.push_back(request);\n-\n-\t\t/* Map memory buffers and cache the mappings. */\n-\t\tconst FrameBuffer::Plane &plane = buffer->planes().front();\n-\t\tvoid *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED,\n-\t\t\t\t plane.fd.fd(), 0);\n-\t\tmappedBuffers_[buffer.get()] = { memory, plane.length };\n \t}\n \n \t/* Start the title timer and the camera. */\n@@ -424,6 +454,8 @@ error:\n \t}\n \tmappedBuffers_.clear();\n \n+\tfreeBuffers_.clear();\n+\n \tdelete allocator_;\n \tallocator_ = nullptr;\n \n@@ -466,6 +498,7 @@ void MainWindow::stopCapture()\n \t * but not processed yet. Clear the queue of done buffers to avoid\n \t * racing with the event handler.\n \t */\n+\tfreeBuffers_.clear();\n \tdoneQueue_.clear();\n \n \ttitleTimer_.stop();\n@@ -505,12 +538,9 @@ void MainWindow::requestComplete(Request *request)\n \t * are not allowed. Add the buffer to the done queue and post a\n \t * CaptureEvent for the application thread to handle.\n \t */\n-\tconst std::map<Stream *, FrameBuffer *> &buffers = request->buffers();\n-\tFrameBuffer *buffer = buffers.begin()->second;\n-\n \t{\n \t\tQMutexLocker locker(&mutex_);\n-\t\tdoneQueue_.enqueue(buffer);\n+\t\tdoneQueue_.enqueue(request->buffers());\n \t}\n \n \tQCoreApplication::postEvent(this, new CaptureEvent);\n@@ -523,16 +553,23 @@ void MainWindow::processCapture()\n \t * if stopCapture() has been called while a CaptureEvent was posted but\n \t * not processed yet. Return immediately in that case.\n \t */\n-\tFrameBuffer *buffer;\n+\tstd::map<Stream *, FrameBuffer *> buffers;\n \n \t{\n \t\tQMutexLocker locker(&mutex_);\n \t\tif (doneQueue_.isEmpty())\n \t\t\treturn;\n \n-\t\tbuffer = doneQueue_.dequeue();\n+\t\tbuffers = doneQueue_.dequeue();\n \t}\n \n+\t/* Process buffers. */\n+\tif (buffers.count(vfStream_))\n+\t\tprocessViewfinder(buffers[vfStream_]);\n+}\n+\n+void MainWindow::processViewfinder(FrameBuffer *buffer)\n+{\n \tframesCaptured_++;\n \n \tconst FrameMetadata &metadata = buffer->metadata();\n@@ -559,8 +596,7 @@ void MainWindow::queueRequest(FrameBuffer *buffer)\n \t\treturn;\n \t}\n \n-\tStream *stream = config_->at(0).stream();\n-\trequest->addBuffer(stream, buffer);\n+\trequest->addBuffer(vfStream_, buffer);\n \n \tcamera_->queueRequest(request);\n }\ndiff --git a/src/qcam/main_window.h b/src/qcam/main_window.h\nindex aea1f1dee20fcbb6..4856ecc10729159c 100644\n--- a/src/qcam/main_window.h\n+++ b/src/qcam/main_window.h\n@@ -69,6 +69,7 @@ private:\n \n \tvoid requestComplete(Request *request);\n \tvoid processCapture();\n+\tvoid processViewfinder(FrameBuffer *buffer);\n \n \t/* UI elements */\n \tQToolBar *toolbar_;\n@@ -95,8 +96,11 @@ private:\n \n \t/* Capture state, buffers queue and statistics */\n \tbool isCapturing_;\n-\tQQueue<FrameBuffer *> doneQueue_;\n-\tQMutex mutex_;\t/* Protects doneQueue_ */\n+\tStream *vfStream_;\n+\tStream *rawStream_;\n+\tstd::map<Stream *, QQueue<FrameBuffer *>> freeBuffers_;\n+\tQQueue<std::map<Stream *, FrameBuffer *>> doneQueue_;\n+\tQMutex mutex_; /* Protects freeBuffers_ and doneQueue_ */\n \n \tuint64_t lastBufferTime_;\n \tQElapsedTimer frameRateInterval_;\n", "prefixes": [ "libcamera-devel", "v4", "1/3" ] }