libcamera: v4l2_videodevice: Reintroduce toV4L2PixelFormat()

This is a partial revert of commit 395d43d6d7 ("libcamera:
v4l2_videodevice: Drop toV4L2PixelFormat()")

The function was removed because it incorrectly maps non-contiguous V4L2
format variants (ie V4L2_PIX_FMT_YUV420M) to the API version supported
by the video device (singleplanar API and multiplanar API).  It was
decided at the time to remove the function and let its users call
directly V4L2PixelFormat::fromPixelFormat() which accepts a
'multiplanar' flags.

As we aim to associate multiple V4L2PixelFormat to a single libcamera
format, the next patches will verify which of them is actually supported
by the video device. For now, return the contiguous version
unconditionally.

Re-introduce V4L2VideoDevice::toV4L2PixelFormat() and convert all
the V4L2PixelFormat::fromPixelFormat() users to use it.

The V4L2 compatibility layer is the only outlier as it doesn't have a
video device to poke, hence it still uses
V4L2PixelFormat::fromPixelFormat().

Next patches will implement the device format matching logic and handle
the non-contiguous plane issue in V4L2VideoDevice::toV4L2PixelFormat().

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Jacopo Mondi 2022-07-15 10:50:41 +02:00
parent 83e0cee0ba
commit 45736468c8
12 changed files with 60 additions and 37 deletions

View file

@ -971,7 +971,8 @@ with the fourcc and size attributes to apply directly to the capture device
node. The fourcc attribute is a `V4L2PixelFormat`_ and differs from the node. The fourcc attribute is a `V4L2PixelFormat`_ and differs from the
``libcamera::PixelFormat``. Converting the format requires knowledge of the ``libcamera::PixelFormat``. Converting the format requires knowledge of the
plane configuration for multiplanar formats, so you must explicitly convert it plane configuration for multiplanar formats, so you must explicitly convert it
using the helper ``V4L2PixelFormat::fromPixelFormat()``. using the helper ``V4L2VideoDevice::toV4L2PixelFormat()`` provided by the
V4L2VideoDevice instance that the format will be applied on.
.. _V4L2DeviceFormat: https://libcamera.org/api-html/classlibcamera_1_1V4L2DeviceFormat.html .. _V4L2DeviceFormat: https://libcamera.org/api-html/classlibcamera_1_1V4L2DeviceFormat.html
.. _V4L2PixelFormat: https://libcamera.org/api-html/classlibcamera_1_1V4L2PixelFormat.html .. _V4L2PixelFormat: https://libcamera.org/api-html/classlibcamera_1_1V4L2PixelFormat.html
@ -981,7 +982,7 @@ Add the following code beneath the code from above:
.. code-block:: cpp .. code-block:: cpp
V4L2DeviceFormat format = {}; V4L2DeviceFormat format = {};
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
Set the video device format defined above using the Set the video device format defined above using the
@ -1001,7 +1002,7 @@ Continue the implementation with the following code:
return ret; return ret;
if (format.size != cfg.size || if (format.size != cfg.size ||
format.fourcc != V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat)) format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat))
return -EINVAL; return -EINVAL;
Finally, store and set stream-specific data reflecting the state of the stream. Finally, store and set stream-specific data reflecting the state of the stream.

View file

@ -228,6 +228,8 @@ public:
static std::unique_ptr<V4L2VideoDevice> static std::unique_ptr<V4L2VideoDevice>
fromEntityName(const MediaDevice *media, const std::string &entity); fromEntityName(const MediaDevice *media, const std::string &entity);
V4L2PixelFormat toV4L2PixelFormat(const PixelFormat &pixelFormat) const;
protected: protected:
std::string logPrefix() const override; std::string logPrefix() const override;

View file

@ -203,7 +203,7 @@ int CIO2Device::configure(const Size &size, V4L2DeviceFormat *outputFormat)
if (itInfo == mbusCodesToPixelFormat.end()) if (itInfo == mbusCodesToPixelFormat.end())
return -EINVAL; return -EINVAL;
outputFormat->fourcc = V4L2PixelFormat::fromPixelFormat(itInfo->second); outputFormat->fourcc = output_->toV4L2PixelFormat(itInfo->second);
outputFormat->size = sensorFormat.size; outputFormat->size = sensorFormat.size;
outputFormat->planesCount = 1; outputFormat->planesCount = 1;

View file

@ -558,7 +558,7 @@ int ImgUDevice::configureVideoDevice(V4L2VideoDevice *dev, unsigned int pad,
return 0; return 0;
*outputFormat = {}; *outputFormat = {};
outputFormat->fourcc = V4L2PixelFormat::fromPixelFormat(formats::NV12); outputFormat->fourcc = dev->toV4L2PixelFormat(formats::NV12);
outputFormat->size = cfg.size; outputFormat->size = cfg.size;
outputFormat->planesCount = 2; outputFormat->planesCount = 2;

View file

@ -90,13 +90,14 @@ PixelFormat mbusCodeToPixelFormat(unsigned int mbus_code,
return pix; return pix;
} }
V4L2DeviceFormat toV4L2DeviceFormat(const V4L2SubdeviceFormat &format, V4L2DeviceFormat toV4L2DeviceFormat(const V4L2VideoDevice *dev,
const V4L2SubdeviceFormat &format,
BayerFormat::Packing packingReq) BayerFormat::Packing packingReq)
{ {
const PixelFormat pix = mbusCodeToPixelFormat(format.mbus_code, packingReq); const PixelFormat pix = mbusCodeToPixelFormat(format.mbus_code, packingReq);
V4L2DeviceFormat deviceFormat; V4L2DeviceFormat deviceFormat;
deviceFormat.fourcc = V4L2PixelFormat::fromPixelFormat(pix); deviceFormat.fourcc = dev->toV4L2PixelFormat(pix);
deviceFormat.size = format.size; deviceFormat.size = format.size;
deviceFormat.colorSpace = format.colorSpace; deviceFormat.colorSpace = format.colorSpace;
return deviceFormat; return deviceFormat;
@ -422,15 +423,15 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
* Calculate the best sensor mode we can use based on * Calculate the best sensor mode we can use based on
* the user request. * the user request.
*/ */
V4L2VideoDevice *unicam = data_->unicam_[Unicam::Image].dev();
const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat); const PixelFormatInfo &info = PixelFormatInfo::info(cfg.pixelFormat);
unsigned int bitDepth = info.isValid() ? info.bitsPerPixel : defaultRawBitDepth; unsigned int bitDepth = info.isValid() ? info.bitsPerPixel : defaultRawBitDepth;
V4L2SubdeviceFormat sensorFormat = findBestFormat(data_->sensorFormats_, cfg.size, bitDepth); V4L2SubdeviceFormat sensorFormat = findBestFormat(data_->sensorFormats_, cfg.size, bitDepth);
BayerFormat::Packing packing = BayerFormat::Packing::CSI2; BayerFormat::Packing packing = BayerFormat::Packing::CSI2;
if (info.isValid() && !info.packed) if (info.isValid() && !info.packed)
packing = BayerFormat::Packing::None; packing = BayerFormat::Packing::None;
V4L2DeviceFormat unicamFormat = toV4L2DeviceFormat(sensorFormat, V4L2DeviceFormat unicamFormat = toV4L2DeviceFormat(unicam, sensorFormat, packing);
packing); int ret = unicam->tryFormat(&unicamFormat);
int ret = data_->unicam_[Unicam::Image].dev()->tryFormat(&unicamFormat);
if (ret) if (ret)
return Invalid; return Invalid;
@ -516,14 +517,14 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
V4L2VideoDevice::Formats fmts = dev->formats(); V4L2VideoDevice::Formats fmts = dev->formats();
if (fmts.find(V4L2PixelFormat::fromPixelFormat(cfgPixFmt)) == fmts.end()) { if (fmts.find(dev->toV4L2PixelFormat(cfgPixFmt)) == fmts.end()) {
/* If we cannot find a native format, use a default one. */ /* If we cannot find a native format, use a default one. */
cfgPixFmt = formats::NV12; cfgPixFmt = formats::NV12;
status = Adjusted; status = Adjusted;
} }
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfgPixFmt); format.fourcc = dev->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
format.colorSpace = cfg.colorSpace; format.colorSpace = cfg.colorSpace;
@ -751,8 +752,9 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
if (ret) if (ret)
return ret; return ret;
V4L2DeviceFormat unicamFormat = toV4L2DeviceFormat(sensorFormat, packing); V4L2VideoDevice *unicam = data->unicam_[Unicam::Image].dev();
ret = data->unicam_[Unicam::Image].dev()->setFormat(&unicamFormat); V4L2DeviceFormat unicamFormat = toV4L2DeviceFormat(unicam, sensorFormat, packing);
ret = unicam->setFormat(&unicamFormat);
if (ret) if (ret)
return ret; return ret;
@ -783,7 +785,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
RPi::Stream *stream = i == maxIndex ? &data->isp_[Isp::Output0] RPi::Stream *stream = i == maxIndex ? &data->isp_[Isp::Output0]
: &data->isp_[Isp::Output1]; : &data->isp_[Isp::Output1];
V4L2PixelFormat fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); V4L2PixelFormat fourcc = stream->dev()->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
format.fourcc = fourcc; format.fourcc = fourcc;
format.colorSpace = cfg.colorSpace; format.colorSpace = cfg.colorSpace;
@ -826,13 +828,15 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
* statistics coming from the hardware. * statistics coming from the hardware.
*/ */
if (!output0Set) { if (!output0Set) {
V4L2VideoDevice *dev = data->isp_[Isp::Output0].dev();
maxSize = Size(320, 240); maxSize = Size(320, 240);
format = {}; format = {};
format.size = maxSize; format.size = maxSize;
format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420); format.fourcc = dev->toV4L2PixelFormat(formats::YUV420);
/* No one asked for output, so the color space doesn't matter. */ /* No one asked for output, so the color space doesn't matter. */
format.colorSpace = ColorSpace::Jpeg; format.colorSpace = ColorSpace::Jpeg;
ret = data->isp_[Isp::Output0].dev()->setFormat(&format); ret = dev->setFormat(&format);
if (ret) { if (ret) {
LOG(RPI, Error) LOG(RPI, Error)
<< "Failed to set default format on ISP Output0: " << "Failed to set default format on ISP Output0: "
@ -856,18 +860,20 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
* colour denoise will not run. * colour denoise will not run.
*/ */
if (!output1Set) { if (!output1Set) {
V4L2VideoDevice *dev = data->isp_[Isp::Output1].dev();
V4L2DeviceFormat output1Format; V4L2DeviceFormat output1Format;
constexpr Size maxDimensions(1200, 1200); constexpr Size maxDimensions(1200, 1200);
const Size limit = maxDimensions.boundedToAspectRatio(format.size); const Size limit = maxDimensions.boundedToAspectRatio(format.size);
output1Format.size = (format.size / 2).boundedTo(limit).alignedDownTo(2, 2); output1Format.size = (format.size / 2).boundedTo(limit).alignedDownTo(2, 2);
output1Format.colorSpace = format.colorSpace; output1Format.colorSpace = format.colorSpace;
output1Format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420); output1Format.fourcc = dev->toV4L2PixelFormat(formats::YUV420);
LOG(RPI, Debug) << "Setting ISP Output1 (internal) to " LOG(RPI, Debug) << "Setting ISP Output1 (internal) to "
<< output1Format; << output1Format;
ret = data->isp_[Isp::Output1].dev()->setFormat(&output1Format); ret = dev->setFormat(&output1Format);
if (ret) { if (ret) {
LOG(RPI, Error) << "Failed to set format on ISP Output1: " LOG(RPI, Error) << "Failed to set format on ISP Output1: "
<< ret; << ret;

View file

@ -81,7 +81,7 @@ CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg)
cfg->bufferCount = RKISP1_BUFFER_COUNT; cfg->bufferCount = RKISP1_BUFFER_COUNT;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg->pixelFormat); format.fourcc = video_->toV4L2PixelFormat(cfg->pixelFormat);
format.size = cfg->size; format.size = cfg->size;
int ret = video_->tryFormat(&format); int ret = video_->tryFormat(&format);
@ -147,7 +147,7 @@ int RkISP1Path::configure(const StreamConfiguration &config,
const PixelFormatInfo &info = PixelFormatInfo::info(config.pixelFormat); const PixelFormatInfo &info = PixelFormatInfo::info(config.pixelFormat);
V4L2DeviceFormat outputFormat; V4L2DeviceFormat outputFormat;
outputFormat.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat); outputFormat.fourcc = video_->toV4L2PixelFormat(config.pixelFormat);
outputFormat.size = config.size; outputFormat.size = config.size;
outputFormat.planesCount = info.numPlanes(); outputFormat.planesCount = info.numPlanes();
@ -156,7 +156,7 @@ int RkISP1Path::configure(const StreamConfiguration &config,
return ret; return ret;
if (outputFormat.size != config.size || if (outputFormat.size != config.size ||
outputFormat.fourcc != V4L2PixelFormat::fromPixelFormat(config.pixelFormat)) { outputFormat.fourcc != video_->toV4L2PixelFormat(config.pixelFormat)) {
LOG(RkISP1, Error) LOG(RkISP1, Error)
<< "Unable to configure capture in " << config.toString(); << "Unable to configure capture in " << config.toString();
return -EINVAL; return -EINVAL;

View file

@ -46,7 +46,7 @@ int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg,
const StreamConfiguration &outputCfg) const StreamConfiguration &outputCfg)
{ {
V4L2PixelFormat videoFormat = V4L2PixelFormat videoFormat =
V4L2PixelFormat::fromPixelFormat(inputCfg.pixelFormat); m2m_->output()->toV4L2PixelFormat(inputCfg.pixelFormat);
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = videoFormat; format.fourcc = videoFormat;
@ -71,7 +71,7 @@ int SimpleConverter::Stream::configure(const StreamConfiguration &inputCfg,
} }
/* Set the pixel format and size on the output. */ /* Set the pixel format and size on the output. */
videoFormat = V4L2PixelFormat::fromPixelFormat(outputCfg.pixelFormat); videoFormat = m2m_->capture()->toV4L2PixelFormat(outputCfg.pixelFormat);
format = {}; format = {};
format.fourcc = videoFormat; format.fourcc = videoFormat;
format.size = outputCfg.size; format.size = outputCfg.size;
@ -210,7 +210,7 @@ std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)
* enumerate the conversion capabilities on its output (V4L2 capture). * enumerate the conversion capabilities on its output (V4L2 capture).
*/ */
V4L2DeviceFormat v4l2Format; V4L2DeviceFormat v4l2Format;
v4l2Format.fourcc = V4L2PixelFormat::fromPixelFormat(input); v4l2Format.fourcc = m2m_->output()->toV4L2PixelFormat(input);
v4l2Format.size = { 1, 1 }; v4l2Format.size = { 1, 1 };
int ret = m2m_->output()->setFormat(&v4l2Format); int ret = m2m_->output()->setFormat(&v4l2Format);
@ -220,7 +220,7 @@ std::vector<PixelFormat> SimpleConverter::formats(PixelFormat input)
return {}; return {};
} }
if (v4l2Format.fourcc != V4L2PixelFormat::fromPixelFormat(input)) { if (v4l2Format.fourcc != m2m_->output()->toV4L2PixelFormat(input)) {
LOG(SimplePipeline, Debug) LOG(SimplePipeline, Debug)
<< "Input format " << input << " not supported."; << "Input format " << input << " not supported.";
return {}; return {};
@ -287,7 +287,7 @@ SimpleConverter::strideAndFrameSize(const PixelFormat &pixelFormat,
const Size &size) const Size &size)
{ {
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(pixelFormat); format.fourcc = m2m_->capture()->toV4L2PixelFormat(pixelFormat);
format.size = size; format.size = size;
int ret = m2m_->capture()->tryFormat(&format); int ret = m2m_->capture()->tryFormat(&format);

View file

@ -918,7 +918,7 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()
return Invalid; return Invalid;
} else { } else {
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
int ret = data_->video_->tryFormat(&format); int ret = data_->video_->tryFormat(&format);
@ -1028,7 +1028,7 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
return ret; return ret;
/* Configure the video node. */ /* Configure the video node. */
V4L2PixelFormat videoFormat = V4L2PixelFormat::fromPixelFormat(pipeConfig->captureFormat); V4L2PixelFormat videoFormat = video->toV4L2PixelFormat(pipeConfig->captureFormat);
V4L2DeviceFormat captureFormat; V4L2DeviceFormat captureFormat;
captureFormat.fourcc = videoFormat; captureFormat.fourcc = videoFormat;

View file

@ -149,7 +149,7 @@ CameraConfiguration::Status UVCCameraConfiguration::validate()
cfg.bufferCount = 4; cfg.bufferCount = 4;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
int ret = data_->video_->tryFormat(&format); int ret = data_->video_->tryFormat(&format);
@ -205,7 +205,7 @@ int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config)
int ret; int ret;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
ret = data->video_->setFormat(&format); ret = data->video_->setFormat(&format);
@ -213,7 +213,7 @@ int PipelineHandlerUVC::configure(Camera *camera, CameraConfiguration *config)
return ret; return ret;
if (format.size != cfg.size || if (format.size != cfg.size ||
format.fourcc != V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat)) format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat))
return -EINVAL; return -EINVAL;
cfg.setStream(&data->stream_); cfg.setStream(&data->stream_);

View file

@ -171,7 +171,7 @@ CameraConfiguration::Status VimcCameraConfiguration::validate()
cfg.bufferCount = 4; cfg.bufferCount = 4;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
int ret = data_->video_->tryFormat(&format); int ret = data_->video_->tryFormat(&format);
@ -275,7 +275,7 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config)
return ret; return ret;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat); format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
ret = data->video_->setFormat(&format); ret = data->video_->setFormat(&format);
@ -283,7 +283,7 @@ int PipelineHandlerVimc::configure(Camera *camera, CameraConfiguration *config)
return ret; return ret;
if (format.size != cfg.size || if (format.size != cfg.size ||
format.fourcc != V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat)) format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat))
return -EINVAL; return -EINVAL;
/* /*
@ -598,7 +598,7 @@ int VimcCameraData::allocateMockIPABuffers()
constexpr unsigned int kBufCount = 2; constexpr unsigned int kBufCount = 2;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::BGR888); format.fourcc = video_->toV4L2PixelFormat(formats::BGR888);
format.size = Size (160, 120); format.size = Size (160, 120);
int ret = video_->setFormat(&format); int ret = video_->setFormat(&format);

View file

@ -1989,6 +1989,20 @@ V4L2VideoDevice::fromEntityName(const MediaDevice *media,
return std::make_unique<V4L2VideoDevice>(mediaEntity); return std::make_unique<V4L2VideoDevice>(mediaEntity);
} }
/**
* \brief Convert \a PixelFormat to its corresponding V4L2 FourCC
* \param[in] pixelFormat The PixelFormat to convert
*
* The V4L2 format variant the function returns the contiguous version
* unconditionally.
*
* \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
*/
V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelFormat) const
{
return V4L2PixelFormat::fromPixelFormat(pixelFormat);
}
/** /**
* \class V4L2M2MDevice * \class V4L2M2MDevice
* \brief Memory-to-Memory video device * \brief Memory-to-Memory video device

View file

@ -72,7 +72,7 @@ int BufferSource::allocate(const StreamConfiguration &config)
} }
format.size = config.size; format.size = config.size;
format.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat); format.fourcc = video->toV4L2PixelFormat(config.pixelFormat);
if (video->setFormat(&format)) { if (video->setFormat(&format)) {
std::cout << "Failed to set format on output device" << std::endl; std::cout << "Failed to set format on output device" << std::endl;
return TestFail; return TestFail;