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>
This commit is contained in:
parent
4f7625cca7
commit
093573db19
2 changed files with 213 additions and 0 deletions
212
test/v4l2_videodevice/v4l2_m2mdevice.cpp
Normal file
212
test/v4l2_videodevice/v4l2_m2mdevice.cpp
Normal file
|
@ -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);
|
Loading…
Add table
Add a link
Reference in a new issue