diff options
Diffstat (limited to 'src/libcamera/pipeline/raspberrypi/delayed_controls.cpp')
-rw-r--r-- | src/libcamera/pipeline/raspberrypi/delayed_controls.cpp | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp b/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp deleted file mode 100644 index 3db92e7d..00000000 --- a/src/libcamera/pipeline/raspberrypi/delayed_controls.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2020, Raspberry Pi Ltd - * - * delayed_controls.cpp - Helper to deal with controls that take effect with a delay - * - * Note: This has been forked from the libcamera core implementation. - */ - -#include "delayed_controls.h" - -#include <libcamera/base/log.h> - -#include <libcamera/controls.h> - -#include "libcamera/internal/v4l2_device.h" - -/** - * \file delayed_controls.h - * \brief Helper to deal with controls that take effect with a delay - */ - -namespace libcamera { - -LOG_DEFINE_CATEGORY(RPiDelayedControls) - -namespace RPi { - -/** - * \class DelayedControls - * \brief Helper to deal with controls that take effect with a delay - * - * Some sensor controls take effect with a delay as the sensor needs time to - * adjust, for example exposure and analog gain. This is a helper class to deal - * with such controls and the intended users are pipeline handlers. - * - * The idea is to extend the concept of the buffer depth of a pipeline the - * application needs to maintain to also cover controls. Just as with buffer - * depth if the application keeps the number of requests queued above the - * control depth the controls are guaranteed to take effect for the correct - * request. The control depth is determined by the control with the greatest - * delay. - */ - -/** - * \struct DelayedControls::ControlParams - * \brief Parameters associated with controls handled by the \a DelayedControls - * helper class - * - * \var ControlParams::delay - * \brief Frame delay from setting the control on a sensor device to when it is - * consumed during framing. - * - * \var ControlParams::priorityWrite - * \brief Flag to indicate that this control must be applied ahead of, and - * separately from the other controls. - * - * Typically set for the \a V4L2_CID_VBLANK control so that the device driver - * does not reject \a V4L2_CID_EXPOSURE control values that may be outside of - * the existing vertical blanking specified bounds, but are within the new - * blanking bounds. - */ - -/** - * \brief Construct a DelayedControls instance - * \param[in] device The V4L2 device the controls have to be applied to - * \param[in] controlParams Map of the numerical V4L2 control ids to their - * associated control parameters. - * - * The control parameters comprise of delays (in frames) and a priority write - * flag. If this flag is set, the relevant control is written separately from, - * and ahead of the rest of the batched controls. - * - * Only controls specified in \a controlParams are handled. If it's desired to - * mix delayed controls and controls that take effect immediately the immediate - * controls must be listed in the \a controlParams map with a delay value of 0. - */ -DelayedControls::DelayedControls(V4L2Device *device, - const std::unordered_map<uint32_t, ControlParams> &controlParams) - : device_(device), maxDelay_(0) -{ - const ControlInfoMap &controls = device_->controls(); - - /* - * Create a map of control ids to delays for controls exposed by the - * device. - */ - for (auto const ¶m : controlParams) { - auto it = controls.find(param.first); - if (it == controls.end()) { - LOG(RPiDelayedControls, Error) - << "Delay request for control id " - << utils::hex(param.first) - << " but control is not exposed by device " - << device_->deviceNode(); - continue; - } - - const ControlId *id = it->first; - - controlParams_[id] = param.second; - - LOG(RPiDelayedControls, Debug) - << "Set a delay of " << controlParams_[id].delay - << " and priority write flag " << controlParams_[id].priorityWrite - << " for " << id->name(); - - maxDelay_ = std::max(maxDelay_, controlParams_[id].delay); - } - - reset(0); -} - -/** - * \brief Reset state machine - * - * Resets the state machine to a starting position based on control values - * retrieved from the device. - */ -void DelayedControls::reset(unsigned int cookie) -{ - queueCount_ = 1; - writeCount_ = 0; - cookies_[0] = cookie; - - /* Retrieve control as reported by the device. */ - std::vector<uint32_t> ids; - for (auto const ¶m : controlParams_) - ids.push_back(param.first->id()); - - ControlList controls = device_->getControls(ids); - - /* Seed the control queue with the controls reported by the device. */ - values_.clear(); - for (const auto &ctrl : controls) { - const ControlId *id = device_->controls().idmap().at(ctrl.first); - /* - * Do not mark this control value as updated, it does not need - * to be written to to device on startup. - */ - values_[id][0] = Info(ctrl.second, false); - } -} - -/** - * \brief Push a set of controls on the queue - * \param[in] controls List of controls to add to the device queue - * - * Push a set of controls to the control queue. This increases the control queue - * depth by one. - * - * \returns true if \a controls are accepted, or false otherwise - */ -bool DelayedControls::push(const ControlList &controls, const unsigned int cookie) -{ - /* Copy state from previous frame. */ - for (auto &ctrl : values_) { - Info &info = ctrl.second[queueCount_]; - info = values_[ctrl.first][queueCount_ - 1]; - info.updated = false; - } - - /* Update with new controls. */ - const ControlIdMap &idmap = device_->controls().idmap(); - for (const auto &control : controls) { - const auto &it = idmap.find(control.first); - if (it == idmap.end()) { - LOG(RPiDelayedControls, Warning) - << "Unknown control " << control.first; - return false; - } - - const ControlId *id = it->second; - - if (controlParams_.find(id) == controlParams_.end()) - return false; - - Info &info = values_[id][queueCount_]; - - info = Info(control.second); - - LOG(RPiDelayedControls, Debug) - << "Queuing " << id->name() - << " to " << info.toString() - << " at index " << queueCount_; - } - - cookies_[queueCount_] = cookie; - queueCount_++; - - return true; -} - -/** - * \brief Read back controls in effect at a sequence number - * \param[in] sequence The sequence number to get controls for - * - * Read back what controls where in effect at a specific sequence number. The - * history is a ring buffer of 16 entries where new and old values coexist. It's - * the callers responsibility to not read too old sequence numbers that have been - * pushed out of the history. - * - * Historic values are evicted by pushing new values onto the queue using - * push(). The max history from the current sequence number that yields valid - * values are thus 16 minus number of controls pushed. - * - * \return The controls at \a sequence number - */ -std::pair<ControlList, unsigned int> DelayedControls::get(uint32_t sequence) -{ - unsigned int index = std::max<int>(0, sequence - maxDelay_); - - ControlList out(device_->controls()); - for (const auto &ctrl : values_) { - const ControlId *id = ctrl.first; - const Info &info = ctrl.second[index]; - - out.set(id->id(), info); - - LOG(RPiDelayedControls, Debug) - << "Reading " << id->name() - << " to " << info.toString() - << " at index " << index; - } - - return { out, cookies_[index] }; -} - -/** - * \brief Inform DelayedControls of the start of a new frame - * \param[in] sequence Sequence number of the frame that started - * - * Inform the state machine that a new frame has started and of its sequence - * number. Any user of these helpers is responsible to inform the helper about - * the start of any frame. This can be connected with ease to the start of a - * exposure (SOE) V4L2 event. - */ -void DelayedControls::applyControls(uint32_t sequence) -{ - LOG(RPiDelayedControls, Debug) << "frame " << sequence << " started"; - - /* - * Create control list peeking ahead in the value queue to ensure - * values are set in time to satisfy the sensor delay. - */ - ControlList out(device_->controls()); - for (auto &ctrl : values_) { - const ControlId *id = ctrl.first; - unsigned int delayDiff = maxDelay_ - controlParams_[id].delay; - unsigned int index = std::max<int>(0, writeCount_ - delayDiff); - Info &info = ctrl.second[index]; - - if (info.updated) { - if (controlParams_[id].priorityWrite) { - /* - * This control must be written now, it could - * affect validity of the other controls. - */ - ControlList priority(device_->controls()); - priority.set(id->id(), info); - device_->setControls(&priority); - } else { - /* - * Batch up the list of controls and write them - * at the end of the function. - */ - out.set(id->id(), info); - } - - LOG(RPiDelayedControls, Debug) - << "Setting " << id->name() - << " to " << info.toString() - << " at index " << index; - - /* Done with this update, so mark as completed. */ - info.updated = false; - } - } - - writeCount_ = sequence + 1; - - while (writeCount_ > queueCount_) { - LOG(RPiDelayedControls, Debug) - << "Queue is empty, auto queue no-op."; - push({}, cookies_[queueCount_ - 1]); - } - - device_->setControls(&out); -} - -} /* namespace RPi */ - -} /* namespace libcamera */ |