An attempt at getting image data back
This commit is contained in:
252
spider-cam/libcamera/test/v4l2_videodevice/buffer_cache.cpp
Normal file
252
spider-cam/libcamera/test/v4l2_videodevice/buffer_cache.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020, Google Inc.
|
||||
*
|
||||
* Test the buffer cache different operation modes
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include <libcamera/formats.h>
|
||||
#include <libcamera/stream.h>
|
||||
|
||||
#include "buffer_source.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
using namespace libcamera;
|
||||
|
||||
namespace {
|
||||
|
||||
class BufferCacheTest : public Test
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Test that a cache with the same size as there are buffers results in
|
||||
* a sequential run over; 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ...
|
||||
*
|
||||
* The test is only valid when the cache size is as least as big as the
|
||||
* number of buffers.
|
||||
*/
|
||||
int testSequential(V4L2BufferCache *cache,
|
||||
const std::vector<std::unique_ptr<FrameBuffer>> &buffers)
|
||||
{
|
||||
for (unsigned int i = 0; i < buffers.size() * 100; i++) {
|
||||
int nBuffer = i % buffers.size();
|
||||
int index = cache->get(*buffers[nBuffer].get());
|
||||
|
||||
if (index != nBuffer) {
|
||||
std::cout << "Expected index " << nBuffer
|
||||
<< " got " << index << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
cache->put(index);
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that randomly putting buffers to the cache always results in a
|
||||
* valid index.
|
||||
*/
|
||||
int testRandom(V4L2BufferCache *cache,
|
||||
const std::vector<std::unique_ptr<FrameBuffer>> &buffers)
|
||||
{
|
||||
std::uniform_int_distribution<> dist(0, buffers.size() - 1);
|
||||
|
||||
for (unsigned int i = 0; i < buffers.size() * 100; i++) {
|
||||
int nBuffer = dist(generator_);
|
||||
int index = cache->get(*buffers[nBuffer].get());
|
||||
|
||||
if (index < 0) {
|
||||
std::cout << "Failed lookup from cache"
|
||||
<< std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
cache->put(index);
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that using a buffer more frequently keeps it hot in the cache at
|
||||
* all times.
|
||||
*/
|
||||
int testHot(V4L2BufferCache *cache,
|
||||
const std::vector<std::unique_ptr<FrameBuffer>> &buffers,
|
||||
unsigned int hotFrequency)
|
||||
{
|
||||
/* Run the random test on the cache to make it messy. */
|
||||
if (testRandom(cache, buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
std::uniform_int_distribution<> dist(0, buffers.size() - 1);
|
||||
|
||||
/* Pick a hot buffer at random and store its index. */
|
||||
int hotBuffer = dist(generator_);
|
||||
int hotIndex = cache->get(*buffers[hotBuffer].get());
|
||||
cache->put(hotIndex);
|
||||
|
||||
/*
|
||||
* Queue hot buffer at the requested frequency and make sure
|
||||
* it stays hot.
|
||||
*/
|
||||
for (unsigned int i = 0; i < buffers.size() * 100; i++) {
|
||||
int nBuffer, index;
|
||||
bool hotQueue = i % hotFrequency == 0;
|
||||
|
||||
if (hotQueue)
|
||||
nBuffer = hotBuffer;
|
||||
else
|
||||
nBuffer = dist(generator_);
|
||||
|
||||
index = cache->get(*buffers[nBuffer].get());
|
||||
|
||||
if (index < 0) {
|
||||
std::cout << "Failed lookup from cache"
|
||||
<< std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (hotQueue && index != hotIndex) {
|
||||
std::cout << "Hot buffer got cold"
|
||||
<< std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
cache->put(index);
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
int testIsEmpty(const std::vector<std::unique_ptr<FrameBuffer>> &buffers)
|
||||
{
|
||||
V4L2BufferCache cache(buffers.size());
|
||||
|
||||
if (!cache.isEmpty())
|
||||
return TestFail;
|
||||
|
||||
for (auto const &buffer : buffers) {
|
||||
FrameBuffer &b = *buffer.get();
|
||||
cache.get(b);
|
||||
}
|
||||
|
||||
if (cache.isEmpty())
|
||||
return TestFail;
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < buffers.size() - 1; i++)
|
||||
cache.put(i);
|
||||
|
||||
if (cache.isEmpty())
|
||||
return TestFail;
|
||||
|
||||
cache.put(i);
|
||||
if (!cache.isEmpty())
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
int init() override
|
||||
{
|
||||
std::random_device rd;
|
||||
unsigned int seed = rd();
|
||||
|
||||
std::cout << "Random seed is " << seed << std::endl;
|
||||
|
||||
generator_.seed(seed);
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
int run() override
|
||||
{
|
||||
const unsigned int numBuffers = 8;
|
||||
|
||||
StreamConfiguration cfg;
|
||||
cfg.pixelFormat = formats::YUYV;
|
||||
cfg.size = Size(600, 800);
|
||||
cfg.bufferCount = numBuffers;
|
||||
|
||||
BufferSource source;
|
||||
int ret = source.allocate(cfg);
|
||||
if (ret != TestPass)
|
||||
return ret;
|
||||
|
||||
const std::vector<std::unique_ptr<FrameBuffer>> &buffers =
|
||||
source.buffers();
|
||||
|
||||
if (buffers.size() != numBuffers) {
|
||||
std::cout << "Got " << buffers.size()
|
||||
<< " buffers, expected " << numBuffers
|
||||
<< std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test cache of same size as there are buffers, the cache is
|
||||
* created from a list of buffers and will be pre-populated.
|
||||
*/
|
||||
V4L2BufferCache cacheFromBuffers(buffers);
|
||||
|
||||
if (testSequential(&cacheFromBuffers, buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
if (testRandom(&cacheFromBuffers, buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
if (testHot(&cacheFromBuffers, buffers, numBuffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
/*
|
||||
* Test cache of same size as there are buffers, the cache is
|
||||
* not pre-populated.
|
||||
*/
|
||||
V4L2BufferCache cacheFromNumbers(numBuffers);
|
||||
|
||||
if (testSequential(&cacheFromNumbers, buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
if (testRandom(&cacheFromNumbers, buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
if (testHot(&cacheFromNumbers, buffers, numBuffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
/*
|
||||
* Test cache half the size of number of buffers used, the cache
|
||||
* is not pre-populated.
|
||||
*/
|
||||
V4L2BufferCache cacheHalf(numBuffers / 2);
|
||||
|
||||
if (testRandom(&cacheHalf, buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
if (testHot(&cacheHalf, buffers, numBuffers / 2) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
/*
|
||||
* Test that the isEmpty function reports the correct result at
|
||||
* various levels of cache fullness.
|
||||
*/
|
||||
if (testIsEmpty(buffers) != TestPass)
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mt19937 generator_;
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
TEST_REGISTER(BufferCacheTest)
|
||||
206
spider-cam/libcamera/test/v4l2_videodevice/buffer_sharing.cpp
Normal file
206
spider-cam/libcamera/test/v4l2_videodevice/buffer_sharing.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 API tests
|
||||
*
|
||||
* Validate the function of exporting buffers from a V4L2VideoDevice and
|
||||
* the ability to import them to another V4L2VideoDevice instance.
|
||||
* Ensure that the Buffers can successfully be queued and dequeued
|
||||
* between both devices.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <libcamera/framebuffer.h>
|
||||
|
||||
#include <libcamera/base/event_dispatcher.h>
|
||||
#include <libcamera/base/thread.h>
|
||||
#include <libcamera/base/timer.h>
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
using namespace libcamera;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class BufferSharingTest : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
BufferSharingTest()
|
||||
: V4L2VideoDeviceTest("vivid", "vivid-000-vid-cap"),
|
||||
output_(nullptr), framesCaptured_(0), framesOutput_(0) {}
|
||||
|
||||
protected:
|
||||
int init()
|
||||
{
|
||||
int ret = V4L2VideoDeviceTest::init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* media_ already represents VIVID */
|
||||
MediaEntity *entity = media_->getEntityByName("vivid-000-vid-out");
|
||||
if (!entity)
|
||||
return TestSkip;
|
||||
|
||||
output_ = new V4L2VideoDevice(entity);
|
||||
if (!output_) {
|
||||
std::cout << "Failed to create output device" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = output_->open();
|
||||
if (ret) {
|
||||
std::cout << "Failed to open output device" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
V4L2DeviceFormat format = {};
|
||||
|
||||
ret = capture_->getFormat(&format);
|
||||
if (ret) {
|
||||
std::cout << "Failed to get capture format" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
format.size.width = 320;
|
||||
format.size.height = 180;
|
||||
|
||||
ret = capture_->setFormat(&format);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set capture format" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = output_->setFormat(&format);
|
||||
if (ret) {
|
||||
std::cout << "Failed to set output format" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = capture_->allocateBuffers(bufferCount, &buffers_);
|
||||
if (ret < 0) {
|
||||
std::cout << "Failed to allocate buffers" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = output_->importBuffers(bufferCount);
|
||||
if (ret < 0) {
|
||||
std::cout << "Failed to import buffers" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void captureBufferReady(FrameBuffer *buffer)
|
||||
{
|
||||
const FrameMetadata &metadata = buffer->metadata();
|
||||
|
||||
std::cout << "Received capture buffer" << std::endl;
|
||||
|
||||
if (metadata.status != FrameMetadata::FrameSuccess)
|
||||
return;
|
||||
|
||||
output_->queueBuffer(buffer);
|
||||
framesCaptured_++;
|
||||
}
|
||||
|
||||
void outputBufferReady(FrameBuffer *buffer)
|
||||
{
|
||||
const FrameMetadata &metadata = buffer->metadata();
|
||||
|
||||
std::cout << "Received output buffer" << std::endl;
|
||||
|
||||
if (metadata.status != FrameMetadata::FrameSuccess)
|
||||
return;
|
||||
|
||||
capture_->queueBuffer(buffer);
|
||||
framesOutput_++;
|
||||
}
|
||||
|
||||
int run()
|
||||
{
|
||||
EventDispatcher *dispatcher = Thread::current()->eventDispatcher();
|
||||
Timer timeout;
|
||||
int ret;
|
||||
|
||||
capture_->bufferReady.connect(this, &BufferSharingTest::captureBufferReady);
|
||||
output_->bufferReady.connect(this, &BufferSharingTest::outputBufferReady);
|
||||
|
||||
for (const std::unique_ptr<FrameBuffer> &buffer : buffers_) {
|
||||
if (capture_->queueBuffer(buffer.get())) {
|
||||
std::cout << "Failed to queue buffer" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = capture_->streamOn();
|
||||
if (ret) {
|
||||
std::cout << "Failed to start streaming on the capture device" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = output_->streamOn();
|
||||
if (ret) {
|
||||
std::cout << "Failed to start streaming on the output device" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
timeout.start(10000ms);
|
||||
while (timeout.isRunning()) {
|
||||
dispatcher->processEvents();
|
||||
if (framesCaptured_ > 30 && framesOutput_ > 30)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((framesCaptured_ < 1) || (framesOutput_ < 1)) {
|
||||
std::cout << "Failed to process any frames within timeout." << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if ((framesCaptured_ < 30) || (framesOutput_ < 30)) {
|
||||
std::cout << "Failed to process 30 frames within timeout." << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = capture_->streamOff();
|
||||
if (ret) {
|
||||
std::cout << "Failed to stop streaming on the capture device" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
ret = output_->streamOff();
|
||||
if (ret) {
|
||||
std::cout << "Failed to stop streaming on the output device" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
std::cout
|
||||
<< "Captured " << framesCaptured_ << " frames and "
|
||||
<< "output " << framesOutput_ << " frames"
|
||||
<< std::endl;
|
||||
|
||||
output_->streamOff();
|
||||
output_->releaseBuffers();
|
||||
output_->close();
|
||||
|
||||
delete output_;
|
||||
|
||||
V4L2VideoDeviceTest::cleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
const unsigned int bufferCount = 4;
|
||||
|
||||
V4L2VideoDevice *output_;
|
||||
|
||||
unsigned int framesCaptured_;
|
||||
unsigned int framesOutput_;
|
||||
};
|
||||
|
||||
TEST_REGISTER(BufferSharingTest)
|
||||
97
spider-cam/libcamera/test/v4l2_videodevice/capture_async.cpp
Normal file
97
spider-cam/libcamera/test/v4l2_videodevice/capture_async.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 API tests
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <libcamera/framebuffer.h>
|
||||
|
||||
#include <libcamera/base/event_dispatcher.h>
|
||||
#include <libcamera/base/thread.h>
|
||||
#include <libcamera/base/timer.h>
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
using namespace libcamera;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class CaptureAsyncTest : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
CaptureAsyncTest()
|
||||
: V4L2VideoDeviceTest("vimc", "Raw Capture 0"), frames(0) {}
|
||||
|
||||
void receiveBuffer(FrameBuffer *buffer)
|
||||
{
|
||||
std::cout << "Buffer received" << std::endl;
|
||||
frames++;
|
||||
|
||||
/* Requeue the buffer for further use. */
|
||||
capture_->queueBuffer(buffer);
|
||||
}
|
||||
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
const unsigned int bufferCount = 8;
|
||||
|
||||
EventDispatcher *dispatcher = Thread::current()->eventDispatcher();
|
||||
Timer timeout;
|
||||
int ret;
|
||||
|
||||
ret = capture_->allocateBuffers(bufferCount, &buffers_);
|
||||
if (ret < 0) {
|
||||
std::cout << "Failed to allocate buffers" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
capture_->bufferReady.connect(this, &CaptureAsyncTest::receiveBuffer);
|
||||
|
||||
for (const std::unique_ptr<FrameBuffer> &buffer : buffers_) {
|
||||
if (capture_->queueBuffer(buffer.get())) {
|
||||
std::cout << "Failed to queue buffer" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = capture_->streamOn();
|
||||
if (ret)
|
||||
return TestFail;
|
||||
|
||||
const unsigned int nFrames = 30;
|
||||
|
||||
timeout.start(500ms * nFrames);
|
||||
while (timeout.isRunning()) {
|
||||
dispatcher->processEvents();
|
||||
if (frames > nFrames)
|
||||
break;
|
||||
}
|
||||
|
||||
if (frames < 1) {
|
||||
std::cout << "Failed to capture any frames within timeout." << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (frames < nFrames) {
|
||||
std::cout << "Failed to capture " << nFrames
|
||||
<< " frames within timeout." << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
std::cout << "Processed " << frames << " frames" << std::endl;
|
||||
|
||||
ret = capture_->streamOff();
|
||||
if (ret)
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int frames;
|
||||
};
|
||||
|
||||
TEST_REGISTER(CaptureAsyncTest)
|
||||
141
spider-cam/libcamera/test/v4l2_videodevice/controls.cpp
Normal file
141
spider-cam/libcamera/test/v4l2_videodevice/controls.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* V4L2 device controls handling test
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <limits.h>
|
||||
|
||||
#include "libcamera/internal/v4l2_videodevice.h"
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
/* These come from the vivid driver. */
|
||||
#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
|
||||
#define VIVID_CID_INTEGER64 (VIVID_CID_CUSTOM_BASE + 3)
|
||||
#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10)
|
||||
|
||||
/* Helper for VIVID_CID_U8_4D_ARRAY control array size: not from kernel. */
|
||||
#define VIVID_CID_U8_ARRAY_SIZE (2 * 3 * 4 * 5)
|
||||
|
||||
using namespace std;
|
||||
using namespace libcamera;
|
||||
|
||||
class V4L2ControlTest : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
V4L2ControlTest()
|
||||
: V4L2VideoDeviceTest("vivid", "vivid-000-vid-cap")
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
const ControlInfoMap &infoMap = capture_->controls();
|
||||
|
||||
/* Test control enumeration. */
|
||||
if (infoMap.empty()) {
|
||||
cerr << "Failed to enumerate controls" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (infoMap.find(V4L2_CID_BRIGHTNESS) == infoMap.end() ||
|
||||
infoMap.find(V4L2_CID_CONTRAST) == infoMap.end() ||
|
||||
infoMap.find(V4L2_CID_SATURATION) == infoMap.end() ||
|
||||
infoMap.find(VIVID_CID_INTEGER64) == infoMap.end() ||
|
||||
infoMap.find(VIVID_CID_U8_4D_ARRAY) == infoMap.end()) {
|
||||
cerr << "Missing controls" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
const ControlInfo &brightness = infoMap.find(V4L2_CID_BRIGHTNESS)->second;
|
||||
const ControlInfo &contrast = infoMap.find(V4L2_CID_CONTRAST)->second;
|
||||
const ControlInfo &saturation = infoMap.find(V4L2_CID_SATURATION)->second;
|
||||
const ControlInfo &int64 = infoMap.find(VIVID_CID_INTEGER64)->second;
|
||||
const ControlInfo &u8 = infoMap.find(VIVID_CID_U8_4D_ARRAY)->second;
|
||||
|
||||
/* Test getting controls. */
|
||||
ControlList ctrls = capture_->getControls({ V4L2_CID_BRIGHTNESS,
|
||||
V4L2_CID_CONTRAST,
|
||||
V4L2_CID_SATURATION,
|
||||
VIVID_CID_INTEGER64,
|
||||
VIVID_CID_U8_4D_ARRAY });
|
||||
if (ctrls.empty()) {
|
||||
cerr << "Failed to get controls" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (ctrls.infoMap() != &infoMap) {
|
||||
cerr << "Incorrect infoMap for retrieved controls" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (ctrls.get(V4L2_CID_BRIGHTNESS).get<int32_t>() == -1 ||
|
||||
ctrls.get(V4L2_CID_CONTRAST).get<int32_t>() == -1 ||
|
||||
ctrls.get(V4L2_CID_SATURATION).get<int32_t>() == -1) {
|
||||
cerr << "Incorrect value for retrieved controls" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
/*
|
||||
* The VIVID_CID_INTEGER64 control can take any value, just test
|
||||
* that its value can be retrieved and has the right type.
|
||||
*/
|
||||
ctrls.get(VIVID_CID_INTEGER64).get<int64_t>();
|
||||
|
||||
uint8_t u8Min = u8.min().get<uint8_t>();
|
||||
uint8_t u8Max = u8.max().get<uint8_t>();
|
||||
|
||||
Span<const uint8_t> u8Span = ctrls.get(VIVID_CID_U8_4D_ARRAY).get<Span<const uint8_t>>();
|
||||
bool valid = std::all_of(u8Span.begin(), u8Span.end(),
|
||||
[&](uint8_t v) { return v >= u8Min && v <= u8Max; });
|
||||
if (!valid) {
|
||||
cerr << "Incorrect value for retrieved array control"
|
||||
<< endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
/* Test setting controls. */
|
||||
ctrls.set(V4L2_CID_BRIGHTNESS, brightness.min());
|
||||
ctrls.set(V4L2_CID_CONTRAST, contrast.max());
|
||||
ctrls.set(V4L2_CID_SATURATION, saturation.min());
|
||||
ctrls.set(VIVID_CID_INTEGER64, int64.min());
|
||||
|
||||
std::array<uint8_t, VIVID_CID_U8_ARRAY_SIZE> u8Values;
|
||||
std::fill(u8Values.begin(), u8Values.end(), u8.min().get<uint8_t>());
|
||||
ctrls.set(VIVID_CID_U8_4D_ARRAY, Span<const uint8_t>(u8Values));
|
||||
|
||||
int ret = capture_->setControls(&ctrls);
|
||||
if (ret) {
|
||||
cerr << "Failed to set controls" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
/* Test setting controls outside of range. */
|
||||
ctrls.set(V4L2_CID_BRIGHTNESS, brightness.min().get<int32_t>() - 1);
|
||||
ctrls.set(V4L2_CID_CONTRAST, contrast.max().get<int32_t>() + 1);
|
||||
ctrls.set(V4L2_CID_SATURATION, saturation.min().get<int32_t>() + 1);
|
||||
|
||||
ret = capture_->setControls(&ctrls);
|
||||
if (ret) {
|
||||
cerr << "Failed to set controls (out of range)" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (ctrls.get(V4L2_CID_BRIGHTNESS) != brightness.min() ||
|
||||
ctrls.get(V4L2_CID_CONTRAST) != contrast.max() ||
|
||||
ctrls.get(V4L2_CID_SATURATION) != saturation.min().get<int32_t>() + 1) {
|
||||
cerr << "Controls not updated when set" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_REGISTER(V4L2ControlTest)
|
||||
102
spider-cam/libcamera/test/v4l2_videodevice/dequeue_watchdog.cpp
Normal file
102
spider-cam/libcamera/test/v4l2_videodevice/dequeue_watchdog.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2022, Ideas on Board Oy.
|
||||
*
|
||||
* libcamera V4L2 dequeue watchdog test
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <libcamera/base/event_dispatcher.h>
|
||||
#include <libcamera/base/thread.h>
|
||||
#include <libcamera/base/timer.h>
|
||||
|
||||
#include <libcamera/framebuffer.h>
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
using namespace libcamera;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class DequeueWatchdogTest : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
DequeueWatchdogTest()
|
||||
: V4L2VideoDeviceTest("vimc", "Raw Capture 0"), frames_(0), barks_(0) {}
|
||||
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
constexpr unsigned int bufferCount = 8;
|
||||
|
||||
EventDispatcher *dispatcher = Thread::current()->eventDispatcher();
|
||||
Timer timeout;
|
||||
|
||||
int ret = capture_->allocateBuffers(bufferCount, &buffers_);
|
||||
if (ret < 0) {
|
||||
std::cout << "Failed to allocate buffers" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
capture_->dequeueTimeout.connect(this, &DequeueWatchdogTest::barkCounter);
|
||||
capture_->setDequeueTimeout(5ms);
|
||||
|
||||
capture_->bufferReady.connect(this, &DequeueWatchdogTest::receiveBuffer);
|
||||
|
||||
for (const std::unique_ptr<FrameBuffer> &buffer : buffers_) {
|
||||
if (capture_->queueBuffer(buffer.get())) {
|
||||
std::cout << "Failed to queue buffer" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = capture_->streamOn();
|
||||
if (ret < 0) {
|
||||
std::cout << "Failed to start streaming" << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
timeout.start(5s);
|
||||
while (timeout.isRunning()) {
|
||||
dispatcher->processEvents();
|
||||
if (frames_ > 5)
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << "Processed " << frames_ << " frames_ and heard "
|
||||
<< barks_ << " barks_" << std::endl;
|
||||
|
||||
if (!barks_) {
|
||||
std::cout << "Failed to hear any barks_." << std::endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
capture_->streamOff();
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
private:
|
||||
void receiveBuffer(FrameBuffer *buffer)
|
||||
{
|
||||
if (buffer->metadata().status == FrameMetadata::FrameCancelled)
|
||||
return;
|
||||
|
||||
std::cout << "Buffer received" << std::endl;
|
||||
frames_++;
|
||||
|
||||
/* Requeue the buffer for further use. */
|
||||
capture_->queueBuffer(buffer);
|
||||
}
|
||||
|
||||
void barkCounter()
|
||||
{
|
||||
std::cout << "Watchdog is barking" << std::endl;
|
||||
barks_++;
|
||||
}
|
||||
|
||||
unsigned int frames_;
|
||||
unsigned int barks_;
|
||||
};
|
||||
|
||||
TEST_REGISTER(DequeueWatchdogTest)
|
||||
41
spider-cam/libcamera/test/v4l2_videodevice/double_open.cpp
Normal file
41
spider-cam/libcamera/test/v4l2_videodevice/double_open.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 API tests
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class DoubleOpen : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
DoubleOpen()
|
||||
: V4L2VideoDeviceTest("vimc", "Raw Capture 0") {}
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Expect failure: The device has already been opened by the
|
||||
* V4L2VideoDeviceTest base class
|
||||
*/
|
||||
ret = capture_->open();
|
||||
if (!ret) {
|
||||
std::cout << "Double open erroneously succeeded" << std::endl;
|
||||
capture_->close();
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
||||
TEST_REGISTER(DoubleOpen)
|
||||
78
spider-cam/libcamera/test/v4l2_videodevice/formats.cpp
Normal file
78
spider-cam/libcamera/test/v4l2_videodevice/formats.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 device format handling test
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <limits.h>
|
||||
|
||||
#include <libcamera/base/utils.h>
|
||||
|
||||
#include "libcamera/internal/v4l2_videodevice.h"
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libcamera;
|
||||
|
||||
class Format : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
Format()
|
||||
: V4L2VideoDeviceTest("vimc", "Raw Capture 0") {}
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
V4L2DeviceFormat format = {};
|
||||
|
||||
int ret = capture_->getFormat(&format);
|
||||
if (ret) {
|
||||
cerr << "Failed to get format" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
format.size = { UINT_MAX, UINT_MAX };
|
||||
ret = capture_->setFormat(&format);
|
||||
if (ret) {
|
||||
cerr << "Failed to set format: image resolution is invalid: "
|
||||
<< "(UINT_MAX x UINT_MAX) but setFormat() should not fail."
|
||||
<< endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (format.size.width == UINT_MAX ||
|
||||
format.size.height == UINT_MAX) {
|
||||
cerr << "Failed to update image format = (UINT_MAX x UINT_MAX)"
|
||||
<< endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint32_t, const char *>> formats{
|
||||
{ V4L2_PIX_FMT_YUYV, "YUYV" },
|
||||
{ 0, "<INVALID>" },
|
||||
{ v4l2_fourcc(0, 1, 2, 3), "...." },
|
||||
{ V4L2_PIX_FMT_Y16_BE, "Y16 -BE" }
|
||||
};
|
||||
|
||||
for (const auto &fmt : formats) {
|
||||
if (V4L2PixelFormat(fmt.first).toString() != fmt.second) {
|
||||
cerr << "Failed to convert V4L2PixelFormat"
|
||||
<< utils::hex(fmt.first) << "to string"
|
||||
<< endl;
|
||||
return TestFail;
|
||||
}
|
||||
}
|
||||
|
||||
if (V4L2PixelFormat().toString() != "<INVALID>") {
|
||||
cerr << "Failed to convert default V4L2PixelFormat to string"
|
||||
<< endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_REGISTER(Format)
|
||||
24
spider-cam/libcamera/test/v4l2_videodevice/meson.build
Normal file
24
spider-cam/libcamera/test/v4l2_videodevice/meson.build
Normal file
@@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
# Tests are listed in order of complexity.
|
||||
# They are not alphabetically sorted.
|
||||
v4l2_videodevice_tests = [
|
||||
{'name': 'double_open', 'sources': ['double_open.cpp']},
|
||||
{'name': 'controls', 'sources': ['controls.cpp']},
|
||||
{'name': 'formats', 'sources': ['formats.cpp']},
|
||||
{'name': 'dequeue_watchdog', 'sources': ['dequeue_watchdog.cpp']},
|
||||
{'name': 'request_buffers', 'sources': ['request_buffers.cpp']},
|
||||
{'name': 'buffer_cache', 'sources': ['buffer_cache.cpp']},
|
||||
{'name': 'stream_on_off', 'sources': ['stream_on_off.cpp']},
|
||||
{'name': 'capture_async', 'sources': ['capture_async.cpp']},
|
||||
{'name': 'buffer_sharing', 'sources': ['buffer_sharing.cpp']},
|
||||
{'name': 'v4l2_m2mdevice', 'sources': ['v4l2_m2mdevice.cpp']},
|
||||
]
|
||||
|
||||
foreach test : v4l2_videodevice_tests
|
||||
exe = executable(test['name'], [test['sources'], 'v4l2_videodevice_test.cpp'],
|
||||
dependencies : libcamera_private,
|
||||
link_with : test_libraries,
|
||||
include_directories : test_includes_internal)
|
||||
test(test['name'], exe, suite : 'v4l2_videodevice', is_parallel : false)
|
||||
endforeach
|
||||
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 API tests
|
||||
*/
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
class RequestBuffersTest : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
RequestBuffersTest()
|
||||
: V4L2VideoDeviceTest("vimc", "Raw Capture 0") {}
|
||||
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
const unsigned int bufferCount = 8;
|
||||
|
||||
int ret = capture_->allocateBuffers(bufferCount, &buffers_);
|
||||
if (ret != bufferCount)
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_REGISTER(RequestBuffersTest)
|
||||
36
spider-cam/libcamera/test/v4l2_videodevice/stream_on_off.cpp
Normal file
36
spider-cam/libcamera/test/v4l2_videodevice/stream_on_off.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 API tests
|
||||
*/
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
class StreamOnStreamOffTest : public V4L2VideoDeviceTest
|
||||
{
|
||||
public:
|
||||
StreamOnStreamOffTest()
|
||||
: V4L2VideoDeviceTest("vimc", "Raw Capture 0") {}
|
||||
protected:
|
||||
int run()
|
||||
{
|
||||
const unsigned int bufferCount = 8;
|
||||
|
||||
int ret = capture_->allocateBuffers(bufferCount, &buffers_);
|
||||
if (ret < 0)
|
||||
return TestFail;
|
||||
|
||||
ret = capture_->streamOn();
|
||||
if (ret)
|
||||
return TestFail;
|
||||
|
||||
ret = capture_->streamOff();
|
||||
if (ret)
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_REGISTER(StreamOnStreamOffTest)
|
||||
211
spider-cam/libcamera/test/v4l2_videodevice/v4l2_m2mdevice.cpp
Normal file
211
spider-cam/libcamera/test/v4l2_videodevice/v4l2_m2mdevice.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/* 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)
|
||||
@@ -0,0 +1,103 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* libcamera V4L2 API tests
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <linux/media-bus-format.h>
|
||||
|
||||
#include "libcamera/internal/device_enumerator.h"
|
||||
#include "libcamera/internal/media_device.h"
|
||||
|
||||
#include "v4l2_videodevice_test.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libcamera;
|
||||
|
||||
int V4L2VideoDeviceTest::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(driver_);
|
||||
dm.add(entity_);
|
||||
|
||||
media_ = enumerator_->search(dm);
|
||||
if (!media_)
|
||||
return TestSkip;
|
||||
|
||||
MediaEntity *entity = media_->getEntityByName(entity_);
|
||||
if (!entity)
|
||||
return TestSkip;
|
||||
|
||||
capture_ = new V4L2VideoDevice(entity);
|
||||
if (!capture_)
|
||||
return TestFail;
|
||||
|
||||
if (!media_->acquire())
|
||||
return TestFail;
|
||||
|
||||
int ret = media_->disableLinks();
|
||||
media_->release();
|
||||
if (ret)
|
||||
return TestFail;
|
||||
|
||||
if (capture_->open())
|
||||
return TestFail;
|
||||
|
||||
V4L2DeviceFormat format = {};
|
||||
if (capture_->getFormat(&format))
|
||||
return TestFail;
|
||||
|
||||
format.size.width = 640;
|
||||
format.size.height = 480;
|
||||
|
||||
if (driver_ == "vimc") {
|
||||
sensor_ = new CameraSensor(media_->getEntityByName("Sensor A"));
|
||||
if (sensor_->init())
|
||||
return TestFail;
|
||||
|
||||
debayer_ = new V4L2Subdevice(media_->getEntityByName("Debayer A"));
|
||||
if (debayer_->open())
|
||||
return TestFail;
|
||||
|
||||
format.fourcc = V4L2PixelFormat(V4L2_PIX_FMT_SBGGR8);
|
||||
|
||||
V4L2SubdeviceFormat subformat = {};
|
||||
subformat.code = MEDIA_BUS_FMT_SBGGR8_1X8;
|
||||
subformat.size = format.size;
|
||||
|
||||
if (sensor_->setFormat(&subformat))
|
||||
return TestFail;
|
||||
|
||||
if (debayer_->setFormat(0, &subformat))
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
if (capture_->setFormat(&format))
|
||||
return TestFail;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
void V4L2VideoDeviceTest::cleanup()
|
||||
{
|
||||
capture_->streamOff();
|
||||
capture_->releaseBuffers();
|
||||
capture_->close();
|
||||
|
||||
delete debayer_;
|
||||
delete sensor_;
|
||||
delete capture_;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2018, Google Inc.
|
||||
*
|
||||
* libcamera v4l2device test base class
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <libcamera/framebuffer.h>
|
||||
|
||||
#include "libcamera/internal/camera_sensor.h"
|
||||
#include "libcamera/internal/device_enumerator.h"
|
||||
#include "libcamera/internal/media_device.h"
|
||||
#include "libcamera/internal/v4l2_subdevice.h"
|
||||
#include "libcamera/internal/v4l2_videodevice.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
class V4L2VideoDeviceTest : public Test
|
||||
{
|
||||
public:
|
||||
V4L2VideoDeviceTest(const char *driver, const char *entity)
|
||||
: driver_(driver), entity_(entity), sensor_(nullptr),
|
||||
debayer_(nullptr), capture_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
int init();
|
||||
void cleanup();
|
||||
|
||||
std::string driver_;
|
||||
std::string entity_;
|
||||
std::unique_ptr<libcamera::DeviceEnumerator> enumerator_;
|
||||
std::shared_ptr<libcamera::MediaDevice> media_;
|
||||
libcamera::CameraSensor *sensor_;
|
||||
libcamera::V4L2Subdevice *debayer_;
|
||||
libcamera::V4L2VideoDevice *capture_;
|
||||
std::vector<std::unique_ptr<libcamera::FrameBuffer>> buffers_;
|
||||
};
|
||||
Reference in New Issue
Block a user