@@ -36,6 +36,7 @@ public:
Camera *camera() const { return camera_; }
bool hasPendingBuffers() const;
+ ControlList &controls();
ControlList &metadata() { return *metadata_; }
bool completeBuffer(FrameBuffer *buffer);
@@ -49,7 +49,7 @@ public:
void reuse(ReuseFlag flags = Default);
- ControlList &controls() { return *controls_; }
+ const ControlList &controls() const { return *controls_; }
const ControlList &metadata() const;
const BufferMap &buffers() const { return bufferMap_; }
int addBuffer(const Stream *stream, FrameBuffer *buffer,
@@ -64,6 +64,31 @@ public:
std::string toString() const;
+ template<typename T, typename V>
+ void setControl(const Control<T> &ctrl, const V &value)
+ {
+ controls_->set(ctrl, value);
+ }
+
+#ifndef __DOXYGEN__
+ template<typename T, typename V, std::size_t Size>
+ void setControl(const Control<Span<const T, Size>> &ctrl,
+ const Span<const V, Size> &values)
+ {
+ controls_->set(ctrl, values);
+ }
+#endif
+
+ void setControls(const ControlList &other)
+ {
+ controls_->merge(other);
+ }
+
+ void setControl(unsigned int id, const ControlValue &value)
+ {
+ controls_->set(id, value);
+ }
+
private:
LIBCAMERA_DISABLE_COPY(Request)
@@ -804,19 +804,19 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
return 0;
/* Translate the Android request settings to libcamera controls. */
- ControlList &controls = descriptor->request_->controls();
+ Request *req = descriptor->request_.get();
camera_metadata_ro_entry_t entry;
if (settings.getEntry(ANDROID_SCALER_CROP_REGION, &entry)) {
const int32_t *data = entry.data.i32;
Rectangle cropRegion{ data[0], data[1],
static_cast<unsigned int>(data[2]),
static_cast<unsigned int>(data[3]) };
- controls.set(controls::ScalerCrop, cropRegion);
+ req->setControl(controls::ScalerCrop, cropRegion);
}
if (settings.getEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, &entry)) {
const uint8_t *data = entry.data.u8;
- controls.set(controls::draft::FaceDetectMode, data[0]);
+ req->setControl(controls::draft::FaceDetectMode, data[0]);
}
if (settings.getEntry(ANDROID_SENSOR_TEST_PATTERN_MODE, &entry)) {
@@ -854,7 +854,7 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
return -EINVAL;
}
- controls.set(controls::draft::TestPatternMode, testPatternMode);
+ req->setControl(controls::draft::TestPatternMode, testPatternMode);
}
return 0;
@@ -447,7 +447,7 @@ int CameraSession::queueRequest(Request *request)
return 0;
if (script_)
- request->controls() = script_->frameControls(queueCount_);
+ request->setControls(script_->frameControls(queueCount_));
queueCount_++;
@@ -276,7 +276,7 @@ void GstCameraControls::setCamera(const std::shared_ptr<libcamera::Camera> &cam)
void GstCameraControls::applyControls(std::unique_ptr<libcamera::Request> &request)
{
- request->controls().merge(controls_);
+ request->setControls(controls_);
controls_.clear();
}
@@ -1366,7 +1366,7 @@ int Camera::queueRequest(Request *request)
}
/* Pre-process AeEnable. */
- patchControlList(request->controls());
+ patchControlList(request->_d()->controls());
d->pipe_->invokeMethod(&PipelineHandler::queueRequest,
ConnectionTypeQueued, request);
@@ -87,6 +87,16 @@ bool Request::Private::hasPendingBuffers() const
return !pending_.empty();
}
+/**
+ * \fn Request::Private::controls()
+ * \brief Retrieve the request's ControlList
+ * \return A reference to the ControlList in this request
+ */
+ControlList &Request::Private::controls()
+{
+ return *_o<Request>()->controls_;
+}
+
/**
* \fn Request::Private::metadata()
* \brief Retrieve the request's metadata
@@ -414,19 +424,9 @@ void Request::reuse(ReuseFlag flags)
}
/**
- * \fn Request::controls()
- * \brief Retrieve the request's ControlList
- *
- * Requests store a list of controls to be applied to all frames captured for
- * the request. They are created with an empty list of controls that can be
- * accessed through this function. Control values can be retrieved using
- * ControlList::get() and updated using ControlList::set().
- *
- * Only controls supported by the camera to which this request will be
- * submitted shall be included in the controls list. Attempting to add an
- * unsupported control causes undefined behaviour.
- *
- * \return A reference to the ControlList in this request
+ * \fn Request::controls() const
+ * \brief Retrieve a const reference to the request's ControlList
+ * \return A const reference to the ControlList in this request
*/
/**
@@ -623,4 +623,24 @@ std::ostream &operator<<(std::ostream &out, const Request &r)
return out;
}
+/**
+ * \fn Request::setControl(const Control<T> &ctrl, const V &value)
+ * \brief Set control \a ctrl in the Request
+ * \param[in] ctrl The control
+ * \param[in] value The control value
+ */
+
+/**
+ * \fn Request::setControls(const ControlList &other)
+ * \brief Merge the control list \a other in the Request
+ * \param[in] other The control list to add to the Request
+ */
+
+/**
+ * \fn Request::setControl(unsigned int id, const ControlValue &value)
+ * \brief Set control \a id in the Request to \a value
+ * \param[in] id The control numerical id
+ * \param[in] value The control value
+ */
+
} /* namespace libcamera */
@@ -463,7 +463,7 @@ PYBIND11_MODULE(_libcamera, m)
.def_property_readonly("sequence", &Request::sequence)
.def_property_readonly("has_pending_buffers", &Request::hasPendingBuffers)
.def("set_control", [](Request &self, const ControlId &id, py::object value) {
- self.controls().set(id.id(), pyToControlValue(value, id.type()));
+ self.setControl(id.id(), pyToControlValue(value, id.type()));
})
.def_property_readonly("metadata", [](Request &self) {
/* Convert ControlList to std container */
@@ -269,7 +269,7 @@ int V4L2Camera::qbuf(unsigned int index)
return 0;
}
- request->controls().merge(std::move(controls_));
+ request->setControls(controls_);
ret = camera_->queueRequest(request);
if (ret < 0) {
The ControlList inside a Request is initialized with the Camera ControlInfoMap, which lists the limits of the controls supported by the Camera. The Request class currently exposes the control list it contains through the Request::controls() function as a raw pointer, potentially allowing applications to replace the Request's control list with a different one. The following pattern: request->controls() = {}; is then currently valid but opens the door to potential issues, as the new list might be initialized with a different info map or without any info map at all. To avoid applications to override the control list contained in a Request, make the Request::controls() function return a const reference and move the non-const version to the Request::Private class for internal usage. Add to the Request class 4 overloads of the setControl() function that allows applications to set controls on a Request control list without accessing it. Closes: https://gitlab.freedesktop.org/camera/libcamera/-/issues/295 Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com> --- include/libcamera/internal/request.h | 1 + include/libcamera/request.h | 27 +++++++++++++++++- src/android/camera_device.cpp | 8 +++--- src/apps/cam/camera_session.cpp | 2 +- src/gstreamer/gstlibcamera-controls.cpp.in | 2 +- src/libcamera/camera.cpp | 2 +- src/libcamera/request.cpp | 46 +++++++++++++++++++++--------- src/py/libcamera/py_main.cpp | 2 +- src/v4l2/v4l2_camera.cpp | 2 +- 9 files changed, 69 insertions(+), 23 deletions(-)