libcamera/test/media_device/media_device_link_test.cpp
Niklas Söderlund 1a813a5c3a libcamera: media_device: Handle media device fd in acquire() and release()
To gain better control of when a file descriptor is open to the media
device and reduce the work needed in pipeline handler implementations,
handle the file descriptor in acquire() and release().

This changes the current behavior where a file descriptor is only open
when requested by the pipeline handler to that one is always open as
long a media device is acquired. This new behavior is desired to allow
implementing exclusive access to a pipeline handler between processes.

Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2019-05-17 01:33:57 +02:00

243 lines
6 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* media_device_link_test.cpp - Tests link handling on VIMC media device
*/
#include <iostream>
#include <memory>
#include "device_enumerator.h"
#include "media_device.h"
#include "test.h"
using namespace libcamera;
using namespace std;
/*
* This link test requires a vimc device in order to exercise the
* MediaObject link handling API on a graph with a predetermined topology.
*
* vimc is a Media Controller kernel driver that creates virtual devices.
* From a userspace point of view they appear as normal media controller
* devices, but are not backed by any particular piece of hardware. They can
* thus be used for testing purpose without depending on a particular hardware
* platform.
*
* If no vimc device is found (most likely because the vimc driver is not
* loaded) the test is skipped.
*/
class MediaDeviceLinkTest : public Test
{
int init()
{
enumerator = unique_ptr<DeviceEnumerator>(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("vimc");
dev_ = enumerator->search(dm);
if (!dev_) {
cerr << "No VIMC media device found: skip test" << endl;
return TestSkip;
}
if (!dev_->acquire()) {
cerr << "Unable to acquire media device "
<< dev_->deviceNode() << endl;
return TestSkip;
}
return 0;
}
int run()
{
/*
* First of all disable all links in the media graph to
* ensure we start from a known state.
*/
if (dev_->disableLinks()) {
cerr << "Failed to disable all links in the media graph";
return TestFail;
}
/*
* Test if link can be consistently retrieved through the
* different methods the media device offers.
*/
string linkName("'Debayer A':[1] -> 'Scaler':[0]'");
MediaLink *link = dev_->link("Debayer A", 1, "Scaler", 0);
if (!link) {
cerr << "Unable to find link: " << linkName
<< " using lookup by name" << endl;
return TestFail;
}
MediaEntity *source = dev_->getEntityByName("Debayer A");
if (!source) {
cerr << "Unable to find entity: 'Debayer A'" << endl;
return TestFail;
}
MediaEntity *sink = dev_->getEntityByName("Scaler");
if (!sink) {
cerr << "Unable to find entity: 'Scaler'" << endl;
return TestFail;
}
MediaLink *link2 = dev_->link(source, 1, sink, 0);
if (!link2) {
cerr << "Unable to find link: " << linkName
<< " using lookup by entity" << endl;
return TestFail;
}
if (link != link2) {
cerr << "Link lookup by name and by entity don't match"
<< endl;
return TestFail;
}
link2 = dev_->link(source->getPadByIndex(1),
sink->getPadByIndex(0));
if (!link2) {
cerr << "Unable to find link: " << linkName
<< " using lookup by pad" << endl;
return TestFail;
}
if (link != link2) {
cerr << "Link lookup by name and by pad don't match"
<< endl;
return TestFail;
}
/* After reset the link shall not be enabled. */
if (link->flags() & MEDIA_LNK_FL_ENABLED) {
cerr << "Link " << linkName
<< " should not be enabled after a device reset"
<< endl;
return TestFail;
}
/* Enable the link and test if enabling was successful. */
if (link->setEnabled(true)) {
cerr << "Failed to enable link: " << linkName
<< endl;
return TestFail;
}
if (!(link->flags() & MEDIA_LNK_FL_ENABLED)) {
cerr << "Link " << linkName
<< " was enabled but it is reported as disabled"
<< endl;
return TestFail;
}
/* Disable the link and test if disabling was successful. */
if (link->setEnabled(false)) {
cerr << "Failed to disable link: " << linkName
<< endl;
return TestFail;
}
if (link->flags() & MEDIA_LNK_FL_ENABLED) {
cerr << "Link " << linkName
<< " was disabled but it is reported as enabled"
<< endl;
return TestFail;
}
/* Try to get a non existing link. */
linkName = "'Sensor A':[1] -> 'Scaler':[0]";
link = dev_->link("Sensor A", 1, "Scaler", 0);
if (link) {
cerr << "Link lookup for " << linkName
<< " succeeded but link does not exist"
<< endl;
return TestFail;
}
/* Now get an immutable link and try to disable it. */
linkName = "'Sensor A':[0] -> 'Raw Capture 0':[0]";
link = dev_->link("Sensor A", 0, "Raw Capture 0", 0);
if (!link) {
cerr << "Unable to find link: " << linkName
<< " using lookup by name" << endl;
return TestFail;
}
if (!(link->flags() & MEDIA_LNK_FL_IMMUTABLE)) {
cerr << "Link " << linkName
<< " should be 'IMMUTABLE'" << endl;
return TestFail;
}
/* Disabling an immutable link shall fail. */
if (!link->setEnabled(false)) {
cerr << "Disabling immutable link " << linkName
<< " succeeded but should have failed" << endl;
return TestFail;
}
/*
* Enable an disabled link, and verify it is disabled again
* after disabling all links in the media graph.
*/
linkName = "'Debayer B':[1] -> 'Scaler':[0]'";
link = dev_->link("Debayer B", 1, "Scaler", 0);
if (!link) {
cerr << "Unable to find link: " << linkName
<< " using lookup by name" << endl;
return TestFail;
}
if (link->setEnabled(true)) {
cerr << "Failed to enable link: " << linkName
<< endl;
return TestFail;
}
if (!(link->flags() & MEDIA_LNK_FL_ENABLED)) {
cerr << "Link " << linkName
<< " was enabled but it is reported as disabled"
<< endl;
return TestFail;
}
if (dev_->disableLinks()) {
cerr << "Failed to disable all links in the media graph";
return TestFail;
}
if (link->flags() & MEDIA_LNK_FL_ENABLED) {
cerr << "All links in the media graph have been disabled"
<< " but link " << linkName
<< " is still reported as enabled" << endl;
return TestFail;
}
return 0;
}
void cleanup()
{
dev_->release();
}
private:
unique_ptr<DeviceEnumerator> enumerator;
shared_ptr<MediaDevice> dev_;
};
TEST_REGISTER(MediaDeviceLinkTest);