[libcamera-devel] [PATCH 9/9] [HACK] test: v4l2_videodevice: Add buffer import test

Jacopo Mondi jacopo at jmondi.org
Fri Jul 5 00:53:34 CEST 2019


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 <jacopo at jmondi.org>

---
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 <iostream>
+
+#include <libcamera/buffer.h>
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/event_dispatcher.h>
+#include <libcamera/timer.h>
+
+#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<Stream *, Buffer *> &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<Request *> 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<Stream *, Buffer *> 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> camera_;
+	std::unique_ptr<CameraConfiguration> 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
-- 
2.21.0



More information about the libcamera-devel mailing list