mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-13 15:29:45 +03:00
libcamera: Add V4L2 Device object
Provide a helper V4L2 device object capable of interacting with the V4L2 Linux Kernel APIs. Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
e399a0745b
commit
e74f3eebb4
3 changed files with 248 additions and 0 deletions
60
src/libcamera/include/v4l2_device.h
Normal file
60
src/libcamera/include/v4l2_device.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019, Google Inc.
|
||||||
|
*
|
||||||
|
* v4l2_device.h - V4L2 Device
|
||||||
|
*/
|
||||||
|
#ifndef __LIBCAMERA_V4L2_DEVICE_H__
|
||||||
|
#define __LIBCAMERA_V4L2_DEVICE_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
struct V4L2Capability final : v4l2_capability {
|
||||||
|
const char *driver() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const char *>(v4l2_capability::driver);
|
||||||
|
}
|
||||||
|
const char *card() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const char *>(v4l2_capability::card);
|
||||||
|
}
|
||||||
|
const char *bus_info() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const char *>(v4l2_capability::bus_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCapture() const { return capabilities & V4L2_CAP_VIDEO_CAPTURE; }
|
||||||
|
bool isOutput() const { return capabilities & V4L2_CAP_VIDEO_OUTPUT; }
|
||||||
|
bool hasStreaming() const { return capabilities & V4L2_CAP_STREAMING; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class V4L2Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
V4L2Device(const std::string &devnode);
|
||||||
|
V4L2Device(const V4L2Device &) = delete;
|
||||||
|
~V4L2Device();
|
||||||
|
|
||||||
|
void operator=(const V4L2Device &) = delete;
|
||||||
|
|
||||||
|
int open();
|
||||||
|
bool isOpen() const;
|
||||||
|
void close();
|
||||||
|
|
||||||
|
const char *driverName() const { return caps_.driver(); }
|
||||||
|
const char *deviceName() const { return caps_.card(); }
|
||||||
|
const char *busName() const { return caps_.bus_info(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string devnode_;
|
||||||
|
int fd_;
|
||||||
|
V4L2Capability caps_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
||||||
|
|
||||||
|
#endif /* __LIBCAMERA_V4L2_DEVICE_H__ */
|
|
@ -11,6 +11,7 @@ libcamera_sources = files([
|
||||||
'pipeline_handler.cpp',
|
'pipeline_handler.cpp',
|
||||||
'signal.cpp',
|
'signal.cpp',
|
||||||
'timer.cpp',
|
'timer.cpp',
|
||||||
|
'v4l2_device.cpp',
|
||||||
])
|
])
|
||||||
|
|
||||||
libcamera_headers = files([
|
libcamera_headers = files([
|
||||||
|
@ -21,6 +22,7 @@ libcamera_headers = files([
|
||||||
'include/media_object.h',
|
'include/media_object.h',
|
||||||
'include/pipeline_handler.h',
|
'include/pipeline_handler.h',
|
||||||
'include/utils.h',
|
'include/utils.h',
|
||||||
|
'include/v4l2_device.h',
|
||||||
])
|
])
|
||||||
|
|
||||||
libcamera_internal_includes = include_directories('include')
|
libcamera_internal_includes = include_directories('include')
|
||||||
|
|
186
src/libcamera/v4l2_device.cpp
Normal file
186
src/libcamera/v4l2_device.cpp
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019, Google Inc.
|
||||||
|
*
|
||||||
|
* v4l2_device.cpp - V4L2 Device
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "v4l2_device.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file v4l2_device.h
|
||||||
|
* \brief V4L2 Device API
|
||||||
|
*/
|
||||||
|
namespace libcamera {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \struct V4L2Capability
|
||||||
|
* \brief struct v4l2_capability object wrapper and helpers
|
||||||
|
*
|
||||||
|
* The V4L2Capability structure manages the information returned by the
|
||||||
|
* VIDIOC_QUERYCAP ioctl.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const char *V4L2Capability::driver()
|
||||||
|
* \brief Retrieve the driver module name
|
||||||
|
* \return The string containing the name of the driver module
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const char *V4L2Capability::card()
|
||||||
|
* \brief Retrieve the device card name
|
||||||
|
* \return The string containing the device name
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const char *V4L2Capability::bus_info()
|
||||||
|
* \brief Retrieve the location of the device in the system
|
||||||
|
* \return The string containing the device location
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn bool V4L2Capability::isCapture()
|
||||||
|
* \brief Identify if the device is capable of capturing video
|
||||||
|
* \return True if the device can capture video frames
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn bool V4L2Capability::isOutput()
|
||||||
|
* \brief Identify if the device is capable of outputting video
|
||||||
|
* \return True if the device can output video frames
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn bool V4L2Capability::hasStreaming()
|
||||||
|
* \brief Determine if the device can perform Streaming I/O
|
||||||
|
* \return True if the device provides Streaming I/O IOCTLs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \class V4L2Device
|
||||||
|
* \brief V4L2Device object and API
|
||||||
|
*
|
||||||
|
* The V4L2 Device API class models an instance of a V4L2 device node.
|
||||||
|
* It is constructed with the path to a V4L2 video device node. The device node
|
||||||
|
* is only opened upon a call to open() which must be checked for success.
|
||||||
|
*
|
||||||
|
* The device capabilities are validated when the device is opened and the
|
||||||
|
* device is rejected if it is not a suitable V4L2 capture or output device, or
|
||||||
|
* if the device does not support streaming I/O.
|
||||||
|
*
|
||||||
|
* No API call other than open(), isOpen() and close() shall be called on an
|
||||||
|
* unopened device instance.
|
||||||
|
*
|
||||||
|
* Upon destruction any device left open will be closed, and any resources
|
||||||
|
* released.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Construct a V4L2Device
|
||||||
|
* \param devnode The file-system path to the video device node
|
||||||
|
*/
|
||||||
|
V4L2Device::V4L2Device(const std::string &devnode)
|
||||||
|
: devnode_(devnode), fd_(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
V4L2Device::~V4L2Device()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Open a V4L2 device and query its capabilities
|
||||||
|
* \return 0 on success, or a negative error code otherwise
|
||||||
|
*/
|
||||||
|
int V4L2Device::open()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (isOpen()) {
|
||||||
|
LOG(Error) << "Device already open";
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ::open(devnode_.c_str(), O_RDWR);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = -errno;
|
||||||
|
LOG(Error) << "Failed to open V4L2 device '" << devnode_
|
||||||
|
<< "': " << strerror(-ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
fd_ = ret;
|
||||||
|
|
||||||
|
ret = ioctl(fd_, VIDIOC_QUERYCAP, &caps_);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = -errno;
|
||||||
|
LOG(Error) << "Failed to query device capabilities: "
|
||||||
|
<< strerror(-ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(Debug) << "Opened '" << devnode_ << "' "
|
||||||
|
<< caps_.bus_info() << ": " << caps_.driver()
|
||||||
|
<< ": " << caps_.card();
|
||||||
|
|
||||||
|
if (!caps_.isCapture() && !caps_.isOutput()) {
|
||||||
|
LOG(Debug) << "Device is not a supported type";
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!caps_.hasStreaming()) {
|
||||||
|
LOG(Error) << "Device does not support streaming I/O";
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check if device is successfully opened
|
||||||
|
* \return True if the device is open, false otherwise
|
||||||
|
*/
|
||||||
|
bool V4L2Device::isOpen() const
|
||||||
|
{
|
||||||
|
return fd_ != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Close the device, releasing any resources acquired by open()
|
||||||
|
*/
|
||||||
|
void V4L2Device::close()
|
||||||
|
{
|
||||||
|
if (fd_ < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
::close(fd_);
|
||||||
|
fd_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const char *V4L2Device::driverName()
|
||||||
|
* \brief Retrieve the name of the V4L2 device driver
|
||||||
|
* \return The string containing the driver name
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const char *V4L2Device::deviceName()
|
||||||
|
* \brief Retrieve the name of the V4L2 device
|
||||||
|
* \return The string containing the device name
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \fn const char *V4L2Device::busName()
|
||||||
|
* \brief Retrieve the location of the device in the system
|
||||||
|
* \return The string containing the device location
|
||||||
|
*/
|
||||||
|
|
||||||
|
} /* namespace libcamera */
|
Loading…
Add table
Add a link
Reference in a new issue