If an exposure time change adjusts the vblanking limits, and we set both VBLANK and EXPOSURE controls through the VIDIOC_S_EXT_CTRLS ioctl, the latter may fail if the value is outside of the limits calculated by the old VBLANK value. This is a limitation in V4L2 and cannot be fixed by setting VBLANK before EXPOSURE in a single VIDIOC_S_EXT_CTRLS ioctl. The workaround here is to have the DelayedControls object mark the VBLANK control as "priority write", which then write VBLANK separately from (and ahead of) any other controls. This way, the sensor driver will update the EXPOSURE control with new limits before the new values is presented, and will thus be seen as valid. To support this, a new struct DelayedControls::ControlParams is used in the constructor to provide the control delay value as well as the priority write flag. Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Tested-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> Tested-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> [Kieran: Fix up trivial comments, merge conflicts] Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
86 lines
1.8 KiB
C++
86 lines
1.8 KiB
C++
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2020, Raspberry Pi (Trading) Ltd.
|
|
*
|
|
* delayed_controls.h - Helper to deal with controls that take effect with a delay
|
|
*/
|
|
#ifndef __LIBCAMERA_INTERNAL_DELAYED_CONTROLS_H__
|
|
#define __LIBCAMERA_INTERNAL_DELAYED_CONTROLS_H__
|
|
|
|
#include <stdint.h>
|
|
#include <unordered_map>
|
|
|
|
#include <libcamera/controls.h>
|
|
|
|
namespace libcamera {
|
|
|
|
class V4L2Device;
|
|
|
|
class DelayedControls
|
|
{
|
|
public:
|
|
struct ControlParams {
|
|
unsigned int delay;
|
|
bool priorityWrite;
|
|
};
|
|
|
|
DelayedControls(V4L2Device *device,
|
|
const std::unordered_map<uint32_t, ControlParams> &controlParams);
|
|
|
|
void reset();
|
|
|
|
bool push(const ControlList &controls);
|
|
ControlList get(uint32_t sequence);
|
|
|
|
void applyControls(uint32_t sequence);
|
|
|
|
private:
|
|
class Info : public ControlValue
|
|
{
|
|
public:
|
|
Info()
|
|
: updated(false)
|
|
{
|
|
}
|
|
|
|
Info(const ControlValue &v)
|
|
: ControlValue(v), updated(true)
|
|
{
|
|
}
|
|
|
|
bool updated;
|
|
};
|
|
|
|
/* \todo: Make the listSize configurable at instance creation time. */
|
|
static constexpr int listSize = 16;
|
|
class ControlRingBuffer : public std::array<Info, listSize>
|
|
{
|
|
public:
|
|
Info &operator[](unsigned int index)
|
|
{
|
|
return std::array<Info, listSize>::operator[](index % listSize);
|
|
}
|
|
|
|
const Info &operator[](unsigned int index) const
|
|
{
|
|
return std::array<Info, listSize>::operator[](index % listSize);
|
|
}
|
|
};
|
|
|
|
V4L2Device *device_;
|
|
/* \todo Evaluate if we should index on ControlId * or unsigned int */
|
|
std::unordered_map<const ControlId *, ControlParams> controlParams_;
|
|
unsigned int maxDelay_;
|
|
|
|
bool running_;
|
|
uint32_t firstSequence_;
|
|
|
|
uint32_t queueCount_;
|
|
uint32_t writeCount_;
|
|
/* \todo Evaluate if we should index on ControlId * or unsigned int */
|
|
std::unordered_map<const ControlId *, ControlRingBuffer> values_;
|
|
};
|
|
|
|
} /* namespace libcamera */
|
|
|
|
#endif /* __LIBCAMERA_INTERNAL_DELAYED_CONTROLS_H__ */
|