[RFC] Per-stream controls

Naushir Patuck naush at raspberrypi.com
Wed Sep 11 10:01:52 CEST 2024


Hi,

This RFC introduces the idea of libcamera controls that can be applied
to one or more specific streams that have been configured via
camera::configure().  One typical use case would be for applying
different ScalerCrop controls for individual streams.

To start with, each StreamConfiguration created from
camera::generateConfiguration() will have a unique id field
(StreamConfiguration::id_) populated by the pipeline handler.  This id
will be used to associate a control with a specific stream.

Next, for setting controls ControlValue::set(const T &value) has a new
overload which accepts a vector of controls and matching vector of
stream ids:

template<typename T>
struct StreamValue {
    unsigned int streamId;
    T value;
};

template<typename T>
void ControlValue::set(const std::vector<StreamValue<T>> &values);

The ControlValue class will need to be updated appropriately to store
the array of values from the above, including ControlValue::reserve().
The existing ControlValue::set(const T &value) implies this control is
set for all streams, exactly the same behavior as we have today.
Similarly, ControlList::set() will have a new prototype:

template<typename T, typename V>
void set(const Control<T> &ctrl, const std::vector<StreamValue <V>> &values)

and ditto for the other set() variant:

template<typename T, typename V, size_t Size>
void set(const Control<Span<T, Size>> &ctrl, const
std::initializer_list<StreamValue<V>> &values)

There should probably be a helper to test if the ControlValue has been
set with one of the new prototypes above:

bool ControlValue::isStreamValue();

Next, on the getting controls T ControlValue::get() is updated with a
new prototype:

template<typename T>
T ControlValue::get(unsigned int streamId = 0)
[maybe this should return std::optional<T> in case streamId is not valid?]

or we could also have

std::StreamValue<T> ControlValue::getSreamValues() that the caller
would have to use if ControlValue::isStreamValue() == true.

The advantage of liking stream ids into the ControlValue directly is
that it propagates nicely into ControlInfo, and we can get
min()/max()/def() values per-stream if the pipeline handler were to
report in such a way.

There are still some questions that I don't have any answers to:
- Should we tag specific controls as having a per-stream value in the
yaml file?  The ControlInfo should hopefully inform the application if
a control is per-stream, but do we need to be more explicit?
- Error handling, what if the user sets a control on an invalid
stream.  How is the error propagated?

There's still quite a bit of implementation detail that is missing
from this proposal, but I think it's a good start for some
discussions.  Let me know your thoughts.

Regards,
Naush


More information about the libcamera-devel mailing list