summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKieran Bingham <kieran.bingham@ideasonboard.com>2019-08-08 15:06:31 +0100
committerKieran Bingham <kieran.bingham@ideasonboard.com>2019-08-13 15:36:04 +0100
commit093573db19179b5bb5e728afe87bd3a610447112 (patch)
tree7663e75354c67ce6e1afbbc7ffa02c6157b88326
parent4f7625cca7ecb4ae5257e7e65ad86d046568db51 (diff)
test: v4l2_videodevice: Add M2M device test
The V4L2M2MDevice requires two video devices to be configured. This makes it unsuitable to reuse the existing V4L2DeviceTest test library in its current form. Implement a full test to run the two M2M pipelines through VIM2M. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
-rw-r--r--test/v4l2_videodevice/meson.build1
-rw-r--r--test/v4l2_videodevice/v4l2_m2mdevice.cpp212
2 files changed, 213 insertions, 0 deletions
diff --git a/test/v4l2_videodevice/meson.build b/test/v4l2_videodevice/meson.build
index 76be5e14..ad41898b 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' ],
+ [ 'v4l2_m2mdevice', 'v4l2_m2mdevice.cpp' ],
]
foreach t : v4l2_videodevice_tests
diff --git a/test/v4l2_videodevice/v4l2_m2mdevice.cpp b/test/v4l2_videodevice/v4l2_m2mdevice.cpp
new file mode 100644
index 00000000..d132b1db
--- /dev/null
+++ b/test/v4l2_videodevice/v4l2_m2mdevice.cpp
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * libcamera V4L2 M2M video device tests
+ */
+
+#include <iostream>
+
+#include <libcamera/buffer.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/event_dispatcher.h>
+#include <libcamera/timer.h>
+
+#include "device_enumerator.h"
+#include "media_device.h"
+#include "v4l2_videodevice.h"
+
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+
+class V4L2M2MDeviceTest : public Test
+{
+public:
+ V4L2M2MDeviceTest()
+ : vim2m_(nullptr), outputFrames_(0), captureFrames_(0)
+ {
+ }
+
+ void outputBufferComplete(Buffer *buffer)
+ {
+ cout << "Received output buffer " << buffer->index() << endl;
+
+ outputFrames_++;
+
+ /* Requeue the buffer for further use. */
+ vim2m_->output()->queueBuffer(buffer);
+ }
+
+ void receiveCaptureBuffer(Buffer *buffer)
+ {
+ cout << "Received capture buffer " << buffer->index() << endl;
+
+ captureFrames_++;
+
+ /* Requeue the buffer for further use. */
+ vim2m_->capture()->queueBuffer(buffer);
+ }
+
+protected:
+ int init()
+ {
+ enumerator_ = DeviceEnumerator::create();
+ if (!enumerator_) {
+ cerr << "Failed to create device enumerator" << endl;
+ return TestFail;
+ }
+
+ if (enumerator_->enumerate()) {
+ cerr << "Failed to enumerate media devices" << endl;
+ return TestFail;
+ }
+
+ DeviceMatch dm("vim2m");
+ dm.add("vim2m-source");
+ dm.add("vim2m-sink");
+
+ media_ = enumerator_->search(dm);
+ if (!media_) {
+ cerr << "No vim2m device found" << endl;
+ return TestSkip;
+ }
+
+ return TestPass;
+ }
+
+ int run()
+ {
+ constexpr unsigned int bufferCount = 4;
+
+ EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher();
+ int ret;
+
+ MediaEntity *entity = media_->getEntityByName("vim2m-source");
+ vim2m_ = new V4L2M2MDevice(entity->deviceNode());
+ if (vim2m_->open()) {
+ cerr << "Failed to open VIM2M device" << endl;
+ return TestFail;
+ }
+
+ V4L2VideoDevice *capture = vim2m_->capture();
+ V4L2VideoDevice *output = vim2m_->output();
+
+ V4L2DeviceFormat format = {};
+ if (capture->getFormat(&format)) {
+ cerr << "Failed to get capture format" << endl;
+ return TestFail;
+ }
+
+ format.size.width = 640;
+ format.size.height = 480;
+
+ if (capture->setFormat(&format)) {
+ cerr << "Failed to set capture format" << endl;
+ return TestFail;
+ }
+
+ if (output->setFormat(&format)) {
+ cerr << "Failed to set output format" << endl;
+ return TestFail;
+ }
+
+ capturePool_.createBuffers(bufferCount);
+ outputPool_.createBuffers(bufferCount);
+
+ ret = capture->exportBuffers(&capturePool_);
+ if (ret) {
+ cerr << "Failed to export Capture Buffers" << endl;
+ return TestFail;
+ }
+
+ ret = output->exportBuffers(&outputPool_);
+ if (ret) {
+ cerr << "Failed to export Output Buffers" << endl;
+ return TestFail;
+ }
+
+ capture->bufferReady.connect(this, &V4L2M2MDeviceTest::receiveCaptureBuffer);
+ output->bufferReady.connect(this, &V4L2M2MDeviceTest::outputBufferComplete);
+
+ std::vector<std::unique_ptr<Buffer>> captureBuffers;
+ captureBuffers = capture->queueAllBuffers();
+ if (captureBuffers.empty()) {
+ cerr << "Failed to queue all Capture Buffers" << endl;
+ return TestFail;
+ }
+
+ /* We can't "queueAllBuffers()" on an output device, so we do it manually */
+ std::vector<std::unique_ptr<Buffer>> outputBuffers;
+ for (unsigned int i = 0; i < outputPool_.count(); ++i) {
+ Buffer *buffer = new Buffer(i);
+ outputBuffers.emplace_back(buffer);
+ ret = output->queueBuffer(buffer);
+ if (ret) {
+ cerr << "Failed to queue output buffer" << i << endl;
+ return TestFail;
+ }
+ }
+
+ ret = capture->streamOn();
+ if (ret) {
+ cerr << "Failed to streamOn capture" << endl;
+ return TestFail;
+ }
+
+ ret = output->streamOn();
+ if (ret) {
+ cerr << "Failed to streamOn output" << endl;
+ return TestFail;
+ }
+
+ Timer timeout;
+ timeout.start(5000);
+ while (timeout.isRunning()) {
+ dispatcher->processEvents();
+ if (captureFrames_ > 30)
+ break;
+ }
+
+ cerr << "Output " << outputFrames_ << " frames" << std::endl;
+ cerr << "Captured " << captureFrames_ << " frames" << std::endl;
+
+ if (captureFrames_ < 30) {
+ cerr << "Failed to capture 30 frames within timeout." << std::endl;
+ return TestFail;
+ }
+
+ ret = capture->streamOff();
+ if (ret) {
+ cerr << "Failed to StreamOff the capture device." << std::endl;
+ return TestFail;
+ }
+
+ ret = output->streamOff();
+ if (ret) {
+ cerr << "Failed to StreamOff the output device." << std::endl;
+ return TestFail;
+ }
+
+ return TestPass;
+ }
+
+ void cleanup()
+ {
+ delete vim2m_;
+ };
+
+private:
+ std::unique_ptr<DeviceEnumerator> enumerator_;
+ std::shared_ptr<MediaDevice> media_;
+ V4L2M2MDevice *vim2m_;
+
+ BufferPool capturePool_;
+ BufferPool outputPool_;
+
+ unsigned int outputFrames_;
+ unsigned int captureFrames_;
+};
+
+TEST_REGISTER(V4L2M2MDeviceTest);