libcamera: ipu3: cio2: Move the CIO2Device class to separate files
In preparation of refactoring the IPU3 pipeline handler breakout the CIO2Device into its own .cpp and .h file, no functional change. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
2cd9556021
commit
6bd3d7259f
4 changed files with 294 additions and 247 deletions
236
src/libcamera/pipeline/ipu3/cio2.cpp
Normal file
236
src/libcamera/pipeline/ipu3/cio2.cpp
Normal file
|
@ -0,0 +1,236 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* cio2.cpp - Intel IPU3 CIO2
|
||||
*/
|
||||
|
||||
#include "cio2.h"
|
||||
|
||||
#include <linux/media-bus-format.h>
|
||||
|
||||
#include "libcamera/internal/camera_sensor.h"
|
||||
#include "libcamera/internal/media_device.h"
|
||||
#include "libcamera/internal/v4l2_subdevice.h"
|
||||
#include "libcamera/internal/v4l2_videodevice.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
LOG_DECLARE_CATEGORY(IPU3)
|
||||
|
||||
CIO2Device::CIO2Device()
|
||||
: output_(nullptr), csi2_(nullptr), sensor_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CIO2Device::~CIO2Device()
|
||||
{
|
||||
delete output_;
|
||||
delete csi2_;
|
||||
delete sensor_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialize components of the CIO2 device with \a index
|
||||
* \param[in] media The CIO2 media device
|
||||
* \param[in] index The CIO2 device index
|
||||
*
|
||||
* Create and open the video device and subdevices in the CIO2 instance at \a
|
||||
* index, if a supported image sensor is connected to the CSI-2 receiver of
|
||||
* this CIO2 instance. Enable the media links connecting the CIO2 components
|
||||
* to prepare for capture operations and cached the sensor maximum size.
|
||||
*
|
||||
* \return 0 on success or a negative error code otherwise
|
||||
* \retval -ENODEV No supported image sensor is connected to this CIO2 instance
|
||||
*/
|
||||
int CIO2Device::init(const MediaDevice *media, unsigned int index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Verify that a sensor subdevice is connected to this CIO2 instance
|
||||
* and enable the media link between the two.
|
||||
*/
|
||||
std::string csi2Name = "ipu3-csi2 " + std::to_string(index);
|
||||
MediaEntity *csi2Entity = media->getEntityByName(csi2Name);
|
||||
const std::vector<MediaPad *> &pads = csi2Entity->pads();
|
||||
if (pads.empty())
|
||||
return -ENODEV;
|
||||
|
||||
/* IPU3 CSI-2 receivers have a single sink pad at index 0. */
|
||||
MediaPad *sink = pads[0];
|
||||
const std::vector<MediaLink *> &links = sink->links();
|
||||
if (links.empty())
|
||||
return -ENODEV;
|
||||
|
||||
MediaLink *link = links[0];
|
||||
MediaEntity *sensorEntity = link->source()->entity();
|
||||
sensor_ = new CameraSensor(sensorEntity);
|
||||
ret = sensor_->init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = link->setEnabled(true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Make sure the sensor produces at least one format compatible with
|
||||
* the CIO2 requirements.
|
||||
*
|
||||
* utils::set_overlap requires the ranges to be sorted, keep the
|
||||
* cio2Codes vector sorted in ascending order.
|
||||
*/
|
||||
const std::vector<unsigned int> cio2Codes{ MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10 };
|
||||
const std::vector<unsigned int> &sensorCodes = sensor_->mbusCodes();
|
||||
if (!utils::set_overlap(sensorCodes.begin(), sensorCodes.end(),
|
||||
cio2Codes.begin(), cio2Codes.end())) {
|
||||
LOG(IPU3, Error)
|
||||
<< "Sensor " << sensor_->entity()->name()
|
||||
<< " has not format compatible with the IPU3";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* \todo Define when to open and close video device nodes, as they
|
||||
* might impact on power consumption.
|
||||
*/
|
||||
|
||||
csi2_ = new V4L2Subdevice(csi2Entity);
|
||||
ret = csi2_->open();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
std::string cio2Name = "ipu3-cio2 " + std::to_string(index);
|
||||
output_ = V4L2VideoDevice::fromEntityName(media, cio2Name);
|
||||
ret = output_->open();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Configure the CIO2 unit
|
||||
* \param[in] size The requested CIO2 output frame size
|
||||
* \param[out] outputFormat The CIO2 unit output image format
|
||||
* \return 0 on success or a negative error code otherwise
|
||||
*/
|
||||
int CIO2Device::configure(const Size &size, V4L2DeviceFormat *outputFormat)
|
||||
{
|
||||
V4L2SubdeviceFormat sensorFormat;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Apply the selected format to the sensor, the CSI-2 receiver and
|
||||
* the CIO2 output device.
|
||||
*/
|
||||
sensorFormat = sensor_->getFormat({ MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10 },
|
||||
size);
|
||||
ret = sensor_->setFormat(&sensorFormat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = csi2_->setFormat(0, &sensorFormat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
V4L2PixelFormat v4l2Format;
|
||||
switch (sensorFormat.mbus_code) {
|
||||
case MEDIA_BUS_FMT_SBGGR10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10);
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SGBRG10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10);
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SGRBG10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10);
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SRGGB10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
outputFormat->fourcc = v4l2Format;
|
||||
outputFormat->size = sensorFormat.size;
|
||||
outputFormat->planesCount = 1;
|
||||
|
||||
ret = output_->setFormat(outputFormat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
LOG(IPU3, Debug) << "CIO2 output format " << outputFormat->toString();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate frame buffers for the CIO2 output
|
||||
*
|
||||
* Allocate frame buffers in the CIO2 video device to be used to capture frames
|
||||
* from the CIO2 output. The buffers are stored in the CIO2Device::buffers_
|
||||
* vector.
|
||||
*
|
||||
* \return Number of buffers allocated or negative error code
|
||||
*/
|
||||
int CIO2Device::allocateBuffers()
|
||||
{
|
||||
int ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (std::unique_ptr<FrameBuffer> &buffer : buffers_)
|
||||
availableBuffers_.push(buffer.get());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CIO2Device::freeBuffers()
|
||||
{
|
||||
/* The default std::queue constructor is explicit with gcc 5 and 6. */
|
||||
availableBuffers_ = std::queue<FrameBuffer *>{};
|
||||
|
||||
buffers_.clear();
|
||||
|
||||
if (output_->releaseBuffers())
|
||||
LOG(IPU3, Error) << "Failed to release CIO2 buffers";
|
||||
}
|
||||
|
||||
FrameBuffer *CIO2Device::getBuffer()
|
||||
{
|
||||
if (availableBuffers_.empty()) {
|
||||
LOG(IPU3, Error) << "CIO2 buffer underrun";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FrameBuffer *buffer = availableBuffers_.front();
|
||||
|
||||
availableBuffers_.pop();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void CIO2Device::putBuffer(FrameBuffer *buffer)
|
||||
{
|
||||
availableBuffers_.push(buffer);
|
||||
}
|
||||
|
||||
int CIO2Device::start()
|
||||
{
|
||||
return output_->streamOn();
|
||||
}
|
||||
|
||||
int CIO2Device::stop()
|
||||
{
|
||||
return output_->streamOff();
|
||||
}
|
||||
|
||||
} /* namespace libcamera */
|
55
src/libcamera/pipeline/ipu3/cio2.h
Normal file
55
src/libcamera/pipeline/ipu3/cio2.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2019, Google Inc.
|
||||
*
|
||||
* cio2.h - Intel IPU3 CIO2
|
||||
*/
|
||||
#ifndef __LIBCAMERA_PIPELINE_IPU3_CIO2_H__
|
||||
#define __LIBCAMERA_PIPELINE_IPU3_CIO2_H__
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
class CameraSensor;
|
||||
class FrameBuffer;
|
||||
class MediaDevice;
|
||||
class V4L2DeviceFormat;
|
||||
class V4L2Subdevice;
|
||||
class V4L2VideoDevice;
|
||||
struct Size;
|
||||
|
||||
class CIO2Device
|
||||
{
|
||||
public:
|
||||
static constexpr unsigned int CIO2_BUFFER_COUNT = 4;
|
||||
|
||||
CIO2Device();
|
||||
~CIO2Device();
|
||||
|
||||
int init(const MediaDevice *media, unsigned int index);
|
||||
int configure(const Size &size, V4L2DeviceFormat *outputFormat);
|
||||
|
||||
int allocateBuffers();
|
||||
void freeBuffers();
|
||||
|
||||
FrameBuffer *getBuffer();
|
||||
void putBuffer(FrameBuffer *buffer);
|
||||
|
||||
int start();
|
||||
int stop();
|
||||
|
||||
V4L2VideoDevice *output_;
|
||||
V4L2Subdevice *csi2_;
|
||||
CameraSensor *sensor_;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<FrameBuffer>> buffers_;
|
||||
std::queue<FrameBuffer *> availableBuffers_;
|
||||
};
|
||||
|
||||
} /* namespace libcamera */
|
||||
|
||||
#endif /* __LIBCAMERA_PIPELINE_IPU3_CIO2_H__ */
|
|
@ -28,6 +28,8 @@
|
|||
#include "libcamera/internal/v4l2_subdevice.h"
|
||||
#include "libcamera/internal/v4l2_videodevice.h"
|
||||
|
||||
#include "cio2.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
LOG_DEFINE_CATEGORY(IPU3)
|
||||
|
@ -104,45 +106,6 @@ public:
|
|||
/* \todo Add param video device for 3A tuning */
|
||||
};
|
||||
|
||||
class CIO2Device
|
||||
{
|
||||
public:
|
||||
static constexpr unsigned int CIO2_BUFFER_COUNT = 4;
|
||||
|
||||
CIO2Device()
|
||||
: output_(nullptr), csi2_(nullptr), sensor_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~CIO2Device()
|
||||
{
|
||||
delete output_;
|
||||
delete csi2_;
|
||||
delete sensor_;
|
||||
}
|
||||
|
||||
int init(const MediaDevice *media, unsigned int index);
|
||||
int configure(const Size &size,
|
||||
V4L2DeviceFormat *outputFormat);
|
||||
|
||||
int allocateBuffers();
|
||||
void freeBuffers();
|
||||
|
||||
FrameBuffer *getBuffer();
|
||||
void putBuffer(FrameBuffer *buffer);
|
||||
|
||||
int start();
|
||||
int stop();
|
||||
|
||||
V4L2VideoDevice *output_;
|
||||
V4L2Subdevice *csi2_;
|
||||
CameraSensor *sensor_;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<FrameBuffer>> buffers_;
|
||||
std::queue<FrameBuffer *> availableBuffers_;
|
||||
};
|
||||
|
||||
class IPU3Stream : public Stream
|
||||
{
|
||||
public:
|
||||
|
@ -1408,214 +1371,6 @@ int ImgUDevice::enableLinks(bool enable)
|
|||
return linkSetup(name_, PAD_STAT, statName, 0, enable);
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* CIO2 Device
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Initialize components of the CIO2 device with \a index
|
||||
* \param[in] media The CIO2 media device
|
||||
* \param[in] index The CIO2 device index
|
||||
*
|
||||
* Create and open the video device and subdevices in the CIO2 instance at \a
|
||||
* index, if a supported image sensor is connected to the CSI-2 receiver of
|
||||
* this CIO2 instance. Enable the media links connecting the CIO2 components
|
||||
* to prepare for capture operations and cached the sensor maximum size.
|
||||
*
|
||||
* \return 0 on success or a negative error code otherwise
|
||||
* \retval -ENODEV No supported image sensor is connected to this CIO2 instance
|
||||
*/
|
||||
int CIO2Device::init(const MediaDevice *media, unsigned int index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Verify that a sensor subdevice is connected to this CIO2 instance
|
||||
* and enable the media link between the two.
|
||||
*/
|
||||
std::string csi2Name = "ipu3-csi2 " + std::to_string(index);
|
||||
MediaEntity *csi2Entity = media->getEntityByName(csi2Name);
|
||||
const std::vector<MediaPad *> &pads = csi2Entity->pads();
|
||||
if (pads.empty())
|
||||
return -ENODEV;
|
||||
|
||||
/* IPU3 CSI-2 receivers have a single sink pad at index 0. */
|
||||
MediaPad *sink = pads[0];
|
||||
const std::vector<MediaLink *> &links = sink->links();
|
||||
if (links.empty())
|
||||
return -ENODEV;
|
||||
|
||||
MediaLink *link = links[0];
|
||||
MediaEntity *sensorEntity = link->source()->entity();
|
||||
sensor_ = new CameraSensor(sensorEntity);
|
||||
ret = sensor_->init();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = link->setEnabled(true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Make sure the sensor produces at least one format compatible with
|
||||
* the CIO2 requirements.
|
||||
*
|
||||
* utils::set_overlap requires the ranges to be sorted, keep the
|
||||
* cio2Codes vector sorted in ascending order.
|
||||
*/
|
||||
const std::vector<unsigned int> cio2Codes{ MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10 };
|
||||
const std::vector<unsigned int> &sensorCodes = sensor_->mbusCodes();
|
||||
if (!utils::set_overlap(sensorCodes.begin(), sensorCodes.end(),
|
||||
cio2Codes.begin(), cio2Codes.end())) {
|
||||
LOG(IPU3, Error)
|
||||
<< "Sensor " << sensor_->entity()->name()
|
||||
<< " has not format compatible with the IPU3";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* \todo Define when to open and close video device nodes, as they
|
||||
* might impact on power consumption.
|
||||
*/
|
||||
|
||||
csi2_ = new V4L2Subdevice(csi2Entity);
|
||||
ret = csi2_->open();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
std::string cio2Name = "ipu3-cio2 " + std::to_string(index);
|
||||
output_ = V4L2VideoDevice::fromEntityName(media, cio2Name);
|
||||
ret = output_->open();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Configure the CIO2 unit
|
||||
* \param[in] size The requested CIO2 output frame size
|
||||
* \param[out] outputFormat The CIO2 unit output image format
|
||||
* \return 0 on success or a negative error code otherwise
|
||||
*/
|
||||
int CIO2Device::configure(const Size &size,
|
||||
V4L2DeviceFormat *outputFormat)
|
||||
{
|
||||
V4L2SubdeviceFormat sensorFormat;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Apply the selected format to the sensor, the CSI-2 receiver and
|
||||
* the CIO2 output device.
|
||||
*/
|
||||
sensorFormat = sensor_->getFormat({ MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10 },
|
||||
size);
|
||||
ret = sensor_->setFormat(&sensorFormat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = csi2_->setFormat(0, &sensorFormat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
V4L2PixelFormat v4l2Format;
|
||||
switch (sensorFormat.mbus_code) {
|
||||
case MEDIA_BUS_FMT_SBGGR10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SBGGR10);
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SGBRG10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGBRG10);
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SGRBG10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SGRBG10);
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SRGGB10_1X10:
|
||||
v4l2Format = V4L2PixelFormat(V4L2_PIX_FMT_IPU3_SRGGB10);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
outputFormat->fourcc = v4l2Format;
|
||||
outputFormat->size = sensorFormat.size;
|
||||
outputFormat->planesCount = 1;
|
||||
|
||||
ret = output_->setFormat(outputFormat);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
LOG(IPU3, Debug) << "CIO2 output format " << outputFormat->toString();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate frame buffers for the CIO2 output
|
||||
*
|
||||
* Allocate frame buffers in the CIO2 video device to be used to capture frames
|
||||
* from the CIO2 output. The buffers are stored in the CIO2Device::buffers_
|
||||
* vector.
|
||||
*
|
||||
* \return Number of buffers allocated or negative error code
|
||||
*/
|
||||
int CIO2Device::allocateBuffers()
|
||||
{
|
||||
int ret = output_->allocateBuffers(CIO2_BUFFER_COUNT, &buffers_);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (std::unique_ptr<FrameBuffer> &buffer : buffers_)
|
||||
availableBuffers_.push(buffer.get());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CIO2Device::freeBuffers()
|
||||
{
|
||||
/* The default std::queue constructor is explicit with gcc 5 and 6. */
|
||||
availableBuffers_ = std::queue<FrameBuffer *>{};
|
||||
|
||||
buffers_.clear();
|
||||
|
||||
if (output_->releaseBuffers())
|
||||
LOG(IPU3, Error) << "Failed to release CIO2 buffers";
|
||||
}
|
||||
|
||||
FrameBuffer *CIO2Device::getBuffer()
|
||||
{
|
||||
if (availableBuffers_.empty()) {
|
||||
LOG(IPU3, Error) << "CIO2 buffer underrun";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FrameBuffer *buffer = availableBuffers_.front();
|
||||
|
||||
availableBuffers_.pop();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void CIO2Device::putBuffer(FrameBuffer *buffer)
|
||||
{
|
||||
availableBuffers_.push(buffer);
|
||||
}
|
||||
|
||||
int CIO2Device::start()
|
||||
{
|
||||
return output_->streamOn();
|
||||
}
|
||||
|
||||
int CIO2Device::stop()
|
||||
{
|
||||
return output_->streamOff();
|
||||
}
|
||||
|
||||
REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3);
|
||||
|
||||
} /* namespace libcamera */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
libcamera_sources += files([
|
||||
'cio2.cpp',
|
||||
'ipu3.cpp',
|
||||
])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue