libcamera: v4l2_videodevice: Drop toV4L2PixelFormat()

The V4L2VideoDevice::toV4L2PixelFormat() function is incorrectly
implemented, as it will pick a multi-planar format if the device
supports the multi-planar API, even if only single-planar formats are
supported. This currently works because the implementation calls
V4L2PixelFormat::fromPixelFormat(), which ignores the multiplanar
argument and always returns a single-planar format.

Fixing this isn't trivial. As we don't need to support multi-planar V4L2
formats at this point, drop the function instead of pretending
everything is fine, and call V4L2PixelFormat::fromPixelFormat() directly
from pipeline handlers. As the single-planar case is the most common,
set the multiplanar argument to false by default to avoid long lines.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Hirokazu Honda <hiroh@chromium.org>
This commit is contained in:
Laurent Pinchart 2021-09-04 01:13:58 +03:00
parent 8e18f8d45f
commit 395d43d6d7
12 changed files with 26 additions and 47 deletions

View file

@ -970,8 +970,7 @@ 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 ``V4L2VideoDevice::toV4L2PixelFormat()`` provided by the using the helper ``V4L2PixelFormat::fromPixelFormat()``.
V4L2VideoDevice instance of which the format will be applied on.
.. _V4L2DeviceFormat: http://libcamera.org/api-html/classlibcamera_1_1V4L2DeviceFormat.html .. _V4L2DeviceFormat: http://libcamera.org/api-html/classlibcamera_1_1V4L2DeviceFormat.html
.. _V4L2PixelFormat: http://libcamera.org/api-html/classlibcamera_1_1V4L2PixelFormat.html .. _V4L2PixelFormat: http://libcamera.org/api-html/classlibcamera_1_1V4L2PixelFormat.html
@ -981,7 +980,7 @@ Add the following code beneath the code from above:
.. code-block:: cpp .. code-block:: cpp
V4L2DeviceFormat format = {}; V4L2DeviceFormat format = {};
format.fourcc = data->video_->toV4L2PixelFormat(cfg.pixelFormat); format.fourcc = V4L2PixelFormat::fromPixelFormat(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 +1000,7 @@ Continue the implementation with the following code:
return ret; return ret;
if (format.size != cfg.size || if (format.size != cfg.size ||
format.fourcc != data->video_->toV4L2PixelFormat(cfg.pixelFormat)) format.fourcc != V4L2PixelFormat::fromPixelFormat(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

@ -38,7 +38,7 @@ public:
PixelFormat toPixelFormat() const; PixelFormat toPixelFormat() const;
static V4L2PixelFormat fromPixelFormat(const PixelFormat &pixelFormat, static V4L2PixelFormat fromPixelFormat(const PixelFormat &pixelFormat,
bool multiplanar); bool multiplanar = false);
private: private:
uint32_t fourcc_; uint32_t fourcc_;

View file

@ -212,8 +212,6 @@ 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);
protected: protected:
std::string logPrefix() const override; std::string logPrefix() const override;

View file

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

View file

@ -440,14 +440,14 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
V4L2VideoDevice::Formats fmts = dev->formats(); V4L2VideoDevice::Formats fmts = dev->formats();
if (fmts.find(V4L2PixelFormat::fromPixelFormat(cfgPixFmt, false)) == fmts.end()) { if (fmts.find(V4L2PixelFormat::fromPixelFormat(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 = dev->toV4L2PixelFormat(cfg.pixelFormat); format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
int ret = dev->tryFormat(&format); int ret = dev->tryFormat(&format);
@ -647,7 +647,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 = stream->dev()->toV4L2PixelFormat(cfg.pixelFormat); V4L2PixelFormat fourcc = V4L2PixelFormat::fromPixelFormat(cfg.pixelFormat);
format.size = cfg.size; format.size = cfg.size;
format.fourcc = fourcc; format.fourcc = fourcc;
@ -688,7 +688,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
maxSize = Size(320, 240); maxSize = Size(320, 240);
format = {}; format = {};
format.size = maxSize; format.size = maxSize;
format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420, false); format.fourcc = V4L2PixelFormat::fromPixelFormat(formats::YUV420);
ret = data->isp_[Isp::Output0].dev()->setFormat(&format); ret = data->isp_[Isp::Output0].dev()->setFormat(&format);
if (ret) { if (ret) {
LOG(RPI, Error) LOG(RPI, Error)

View file

@ -80,7 +80,7 @@ CameraConfiguration::Status RkISP1Path::validate(StreamConfiguration *cfg)
cfg->bufferCount = RKISP1_BUFFER_COUNT; cfg->bufferCount = RKISP1_BUFFER_COUNT;
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = video_->toV4L2PixelFormat(cfg->pixelFormat); format.fourcc = V4L2PixelFormat::fromPixelFormat(cfg->pixelFormat);
format.size = cfg->size; format.size = cfg->size;
int ret = video_->tryFormat(&format); int ret = video_->tryFormat(&format);
@ -146,7 +146,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 = video_->toV4L2PixelFormat(config.pixelFormat); outputFormat.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat);
outputFormat.size = config.size; outputFormat.size = config.size;
outputFormat.planesCount = info.numPlanes(); outputFormat.planesCount = info.numPlanes();
@ -155,7 +155,7 @@ int RkISP1Path::configure(const StreamConfiguration &config,
return ret; return ret;
if (outputFormat.size != config.size || if (outputFormat.size != config.size ||
outputFormat.fourcc != video_->toV4L2PixelFormat(config.pixelFormat)) { outputFormat.fourcc != V4L2PixelFormat::fromPixelFormat(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 =
m2m_->output()->toV4L2PixelFormat(inputCfg.pixelFormat); V4L2PixelFormat::fromPixelFormat(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 = m2m_->capture()->toV4L2PixelFormat(outputCfg.pixelFormat); videoFormat = V4L2PixelFormat::fromPixelFormat(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 = m2m_->output()->toV4L2PixelFormat(input); v4l2Format.fourcc = V4L2PixelFormat::fromPixelFormat(input);
v4l2Format.size = { 1, 1 }; v4l2Format.size = { 1, 1 };
int ret = m2m_->output()->setFormat(&v4l2Format); int ret = m2m_->output()->setFormat(&v4l2Format);
@ -281,7 +281,7 @@ SimpleConverter::strideAndFrameSize(const PixelFormat &pixelFormat,
const Size &size) const Size &size)
{ {
V4L2DeviceFormat format; V4L2DeviceFormat format;
format.fourcc = m2m_->capture()->toV4L2PixelFormat(pixelFormat); format.fourcc = V4L2PixelFormat::fromPixelFormat(pixelFormat);
format.size = size; format.size = size;
int ret = m2m_->capture()->tryFormat(&format); int ret = m2m_->capture()->tryFormat(&format);

View file

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

View file

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

View file

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

View file

@ -1687,23 +1687,6 @@ 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
*
* For multiplanar formats, the V4L2 format variant (contiguous or
* non-contiguous planes) is selected automatically based on the capabilities
* of the video device. If the video device supports the V4L2 multiplanar API,
* non-contiguous formats are preferred.
*
* \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
*/
V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelFormat)
{
return V4L2PixelFormat::fromPixelFormat(pixelFormat,
caps_.isMultiplanar());
}
/** /**
* \class V4L2M2MDevice * \class V4L2M2MDevice
* \brief Memory-to-Memory video device * \brief Memory-to-Memory video device

View file

@ -70,8 +70,7 @@ int BufferSource::allocate(const StreamConfiguration &config)
} }
format.size = config.size; format.size = config.size;
format.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat, format.fourcc = V4L2PixelFormat::fromPixelFormat(config.pixelFormat);
false);
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;