From patchwork Thu Jul 4 22:53:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1630 Return-Path: Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 380BD6156F for ; Fri, 5 Jul 2019 00:52:33 +0200 (CEST) X-Originating-IP: 2.224.242.101 Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id C49471C0008; Thu, 4 Jul 2019 22:52:32 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Fri, 5 Jul 2019 00:53:34 +0200 Message-Id: <20190704225334.26170-10-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190704225334.26170-1-jacopo@jmondi.org> References: <20190704225334.26170-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 9/9] [HACK] test: v4l2_videodevice: Add buffer import test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Jul 2019 22:52:33 -0000 Test buffer importing by streaming the camera to a video output device performing zero-copy memory sharing using dmabuf file descriptors. Not-yet-Signed-off-by: Jacopo Mondi --- Not suitable for merge yes. More a test utility for development at the moment. To be morhped into a camera test from a video device one. --- test/v4l2_videodevice/buffer_import.cpp | 234 ++++++++++++++++++++++++ test/v4l2_videodevice/meson.build | 1 + 2 files changed, 235 insertions(+) create mode 100644 test/v4l2_videodevice/buffer_import.cpp diff --git a/test/v4l2_videodevice/buffer_import.cpp b/test/v4l2_videodevice/buffer_import.cpp new file mode 100644 index 000000000000..0a294b055af5 --- /dev/null +++ b/test/v4l2_videodevice/buffer_import.cpp @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * libcamera V4L2 API tests + * + * Test importing buffers exported from an output device into a camera + */ + +#include + +#include +#include +#include +#include +#include + +#include "v4l2_videodevice_test.h" + +using namespace libcamera; +using namespace std; + +class BufferImportTest : public V4L2VideoDeviceTest +{ +public: + BufferImportTest() + : V4L2VideoDeviceTest("vivid", "vivid-000-vid-out") + { + } + +protected: + void cameraBufferComplete(Request *request, Buffer *buffer) + { + if (buffer->status() != Buffer::BufferSuccess) + return; + + capture_->queueBuffer(buffer); + } + + void requestComplete(Request *request, const std::map &buffers) + { + if (request->status() != Request::RequestComplete) + return; + + /* Reuse the buffers for a new request. */ + request = camera_->createRequest(); + request->setBuffers(buffers); + camera_->queueRequest(request); + } + + int init() + { + constexpr unsigned int bufferCount = 4; + + /* Get a camera where to capture frames from. */ + cm_ = CameraManager::instance(); + + if (cm_->start()) { + cout << "Failed to start camera manager" << endl; + return TestFail; + } + + camera_ = cm_->get("Integrated Camera: Integrated C"); + if (!camera_) { + cout << "Can not find VIMC camera" << endl; + return TestSkip; + } + + if (camera_->acquire()) { + cout << "Failed to acquire the camera" << endl; + return TestFail; + } + + /* + * Initialize the output device and export buffers in a pool. + * The 'output' device is actually called capture_ by the base + * class. + */ + int ret = V4L2VideoDeviceTest::init(); + if (ret) { + cerr << "Failed to initialize output device" << endl; + return ret; + } + + /* + * Set a known format on the output devices, then apply it + * to the camera. + */ + V4L2DeviceFormat format = {}; + if (capture_->getFormat(&format)) { + cleanup(); + return TestFail; + } + + format.size.width = 640; + format.size.height = 480; + format.fourcc = V4L2_PIX_FMT_YUYV; + format.planesCount = 1; + format.planes[0].size = 640 * 480 * 2; + format.planes[0].bpl = 640 * 2; + if (capture_->setFormat(&format)) { + cleanup(); + return TestFail; + } + + cout << "Output format: " << format.toString(); + + config_ = camera_->generateConfiguration({ StreamRole::VideoRecording }); + if (!config_ || config_->size() != 1) { + cout << "Failed to generate default configuration" << endl; + cleanup(); + return TestFail; + } + + /* + * Configure the Stream to work with externally allocated + * buffers by setting the memoryType to ExternalMemory. + */ + StreamConfiguration &cfg = config_->at(0); + cfg.size = format.size; + cfg.pixelFormat = format.fourcc; + cfg.memoryType = ExternalMemory; + + if (camera_->configure(config_.get())) { + cout << "Failed to set modified configuration" << endl; + cleanup(); + return TestFail; + } + cout << "Capture format: " << format.toString(); + + /* + * Export the output buffers to a pool and then import + * them before setting up buffers in the Camera. + */ + pool_.createBuffers(bufferCount); + ret = capture_->exportBuffers(&pool_); + if (ret) { + std::cout << "Failed to export buffers" << std::endl; + cleanup(); + return TestFail; + } + + if (camera_->allocateBuffers()) { + cout << "Failed to allocate buffers" << endl; + return TestFail; + } + + return TestPass; + } + + int run() + { + std::vector requests; + StreamConfiguration &cfg = config_->at(0); + Stream *stream = cfg.stream(); + /* Create one request for each output video buffer. */ + for (Buffer &buffer : pool_.buffers()) { + Request *request = camera_->createRequest(); + if (!request) { + cout << "Failed to create request" << endl; + return TestFail; + } + + std::map map = { { stream, &buffer } }; + if (request->setBuffers(map)) { + cout << "Failed to associating buffer with request" << endl; + return TestFail; + } + + requests.push_back(request); + } + + /* Connect the buffer ready signals of camera and output */ + camera_->bufferCompleted.connect(this, + &BufferImportTest::cameraBufferComplete); + + /* Connect the request ready signal to re-queue requests. */ + camera_->requestCompleted.connect(this, + &BufferImportTest::requestComplete); + + capture_->streamOn(); + if (camera_->start()) { + cout << "Failed to start camera" << endl; + return TestFail; + } + + for (Request *request : requests) { + if (camera_->queueRequest(request)) { + cout << "Failed to queue request" << endl; + camera_->stop(); + capture_->streamOff(); + cleanup(); + return TestFail; + } + } + + EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher(); + + Timer timer; + timer.start(2000); + while (timer.isRunning()) + dispatcher->processEvents(); + + if (camera_->stop()) { + cout << "Failed to stop camera" << endl; + return TestFail; + } + + capture_->streamOff(); + + return TestPass; + } + + void cleanup() + { + camera_->freeBuffers(); + + if (camera_) { + camera_->release(); + camera_.reset(); + } + + cm_->stop(); + + V4L2VideoDeviceTest::cleanup(); + } + +private: + CameraManager *cm_; + std::shared_ptr camera_; + std::unique_ptr config_; +}; + +TEST_REGISTER(BufferImportTest); diff --git a/test/v4l2_videodevice/meson.build b/test/v4l2_videodevice/meson.build index 76be5e142bb6..15169abe48d3 100644 --- a/test/v4l2_videodevice/meson.build +++ b/test/v4l2_videodevice/meson.build @@ -7,6 +7,7 @@ v4l2_videodevice_tests = [ [ 'stream_on_off', 'stream_on_off.cpp' ], [ 'capture_async', 'capture_async.cpp' ], [ 'buffer_sharing', 'buffer_sharing.cpp' ], + [ 'buffer_import', 'buffer_import.cpp' ], ] foreach t : v4l2_videodevice_tests