212 lines
4.7 KiB
C++
212 lines
4.7 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2019, Google Inc.
|
|
*
|
|
* libcamera V4L2 M2M video device tests
|
|
*/
|
|
|
|
#include <iostream>
|
|
|
|
#include <libcamera/framebuffer.h>
|
|
|
|
#include <libcamera/base/event_dispatcher.h>
|
|
#include <libcamera/base/thread.h>
|
|
#include <libcamera/base/timer.h>
|
|
|
|
#include "libcamera/internal/device_enumerator.h"
|
|
#include "libcamera/internal/media_device.h"
|
|
#include "libcamera/internal/v4l2_videodevice.h"
|
|
|
|
#include "test.h"
|
|
|
|
using namespace libcamera;
|
|
using namespace std;
|
|
using namespace std::chrono_literals;
|
|
|
|
class V4L2M2MDeviceTest : public Test
|
|
{
|
|
public:
|
|
V4L2M2MDeviceTest()
|
|
: vim2m_(nullptr), outputFrames_(0), captureFrames_(0)
|
|
{
|
|
}
|
|
|
|
void outputBufferComplete(FrameBuffer *buffer)
|
|
{
|
|
cout << "Received output buffer" << endl;
|
|
|
|
outputFrames_++;
|
|
|
|
/* Requeue the buffer for further use. */
|
|
vim2m_->output()->queueBuffer(buffer);
|
|
}
|
|
|
|
void receiveCaptureBuffer(FrameBuffer *buffer)
|
|
{
|
|
cout << "Received capture buffer" << 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 = Thread::current()->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();
|
|
|
|
if (capture->controls().empty() || output->controls().empty()) {
|
|
cerr << "VIM2M device has no control" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
ret = capture->allocateBuffers(bufferCount, &captureBuffers_);
|
|
if (ret < 0) {
|
|
cerr << "Failed to allocate Capture Buffers" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
ret = output->allocateBuffers(bufferCount, &outputBuffers_);
|
|
if (ret < 0) {
|
|
cerr << "Failed to allocate Output Buffers" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
capture->bufferReady.connect(this, &V4L2M2MDeviceTest::receiveCaptureBuffer);
|
|
output->bufferReady.connect(this, &V4L2M2MDeviceTest::outputBufferComplete);
|
|
|
|
for (const std::unique_ptr<FrameBuffer> &buffer : captureBuffers_) {
|
|
if (capture->queueBuffer(buffer.get())) {
|
|
std::cout << "Failed to queue capture buffer" << std::endl;
|
|
return TestFail;
|
|
}
|
|
}
|
|
|
|
for (const std::unique_ptr<FrameBuffer> &buffer : outputBuffers_) {
|
|
if (output->queueBuffer(buffer.get())) {
|
|
std::cout << "Failed to queue output buffer" << std::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(5000ms);
|
|
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_;
|
|
|
|
std::vector<std::unique_ptr<FrameBuffer>> captureBuffers_;
|
|
std::vector<std::unique_ptr<FrameBuffer>> outputBuffers_;
|
|
|
|
unsigned int outputFrames_;
|
|
unsigned int captureFrames_;
|
|
};
|
|
|
|
TEST_REGISTER(V4L2M2MDeviceTest)
|