[libcamera-devel] [RFC 8/8] test: v4l2_videodevice: Add buffer import test
Jacopo Mondi
jacopo at jmondi.org
Sun Jun 30 20:10:49 CEST 2019
Test buffer importing by streaming the camera to a video output device
performing zero-copy memory sharing using dmabuf file descriptors.
Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
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