Files
external_libcamera/src/gstreamer/gstlibcamera-controls.cpp.in
T
Umang JainandKieran Bingham 0794edcae6 gstreamer: Move existing GValue helpers to gstreamer-utils
Move the existing GValue helpers from gstlibcamera-controls.cpp.in
to gstreamer-utils.cpp. The intention here is to make these helpers
available to other parts of gstreamer source element, for example,
reporting camera properties in GstDeviceProvider.

The function signature has been changed to match with the other
gstreamer-utils utility functions:

value_get_rectangle() =>  gst_libcamera_gvalue_get_rectangle()
value_set_rectangle() =>  gst_libcamera_gvalue_set_rectangle()
value_set_point()     =>  gst_libcamera_gvalue_set_point()
value_set_size()      =>  gst_libcamera_gvalue_set_size()

Signed-off-by: Umang Jain <uajain@igalia.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2025-08-06 19:04:44 +01:00

288 lines
7.8 KiB
Plaintext

/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024, Jaslo Ziska
*
* GStreamer Camera Controls
*
* This file is auto-generated. Do not edit.
*/
#include <vector>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/geometry.h>
#include "gstlibcamera-controls.h"
#include "gstlibcamera-utils.h"
using namespace libcamera;
{% for vendor, ctrls in controls %}
{%- for ctrl in ctrls if ctrl.is_enum %}
static const GEnumValue {{ ctrl.name|snake_case }}_types[] = {
{%- for enum in ctrl.enum_values %}
{
controls::{{ ctrl.namespace }}{{ enum.name }},
{{ enum.description|format_description|indent_str('\t\t') }},
"{{ enum.gst_name }}"
},
{%- endfor %}
{0, nullptr, nullptr}
};
#define TYPE_{{ ctrl.name|snake_case|upper }} \
({{ ctrl.name|snake_case }}_get_type())
static GType {{ ctrl.name|snake_case }}_get_type()
{
static GType {{ ctrl.name|snake_case }}_type = 0;
if (!{{ ctrl.name|snake_case }}_type)
{{ ctrl.name|snake_case }}_type =
g_enum_register_static("{{ ctrl.name }}",
{{ ctrl.name|snake_case }}_types);
return {{ ctrl.name|snake_case }}_type;
}
{% endfor %}
{%- endfor %}
void GstCameraControls::installProperties(GObjectClass *klass, int lastPropId)
{
{%- for vendor, ctrls in controls %}
{%- for ctrl in ctrls %}
{%- set spec %}
{%- if ctrl.is_rectangle -%}
gst_param_spec_array(
{%- else -%}
g_param_spec_{{ ctrl.gtype }}(
{%- endif -%}
{%- if ctrl.is_array %}
"{{ ctrl.vendor_prefix }}{{ ctrl.name|kebab_case }}-value",
"{{ ctrl.name }} Value",
"One {{ ctrl.name }} element value",
{%- else %}
"{{ ctrl.vendor_prefix }}{{ ctrl.name|kebab_case }}",
"{{ ctrl.name }}",
{{ ctrl.description|format_description|indent_str('\t') }},
{%- endif %}
{%- if ctrl.is_enum %}
TYPE_{{ ctrl.name|snake_case|upper }},
{{ ctrl.default }},
{%- elif ctrl.is_rectangle %}
g_param_spec_int(
"rectangle-value",
"Rectangle Value",
"One rectangle value, either x, y, width or height.",
{{ ctrl.min }}, {{ ctrl.max }}, {{ ctrl.default }},
(GParamFlags) (GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)
),
{%- elif ctrl.gtype == 'boolean' %}
{{ ctrl.default }},
{%- elif ctrl.gtype in ['float', 'int', 'int64', 'uchar'] %}
{{ ctrl.min }}, {{ ctrl.max }}, {{ ctrl.default }},
{%- endif %}
(GParamFlags) (GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)
)
{%- endset %}
g_object_class_install_property(
klass,
lastPropId + controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }},
{%- if ctrl.is_array %}
gst_param_spec_array(
"{{ ctrl.vendor_prefix }}{{ ctrl.name|kebab_case }}",
"{{ ctrl.name }}",
{{ ctrl.description|format_description|indent_str('\t\t\t') }},
{{ spec|indent_str('\t\t\t') }},
(GParamFlags) (GST_PARAM_CONTROLLABLE |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)
)
{%- else %}
{{ spec|indent_str('\t\t') }}
{%- endif %}
);
{%- endfor %}
{%- endfor %}
}
bool GstCameraControls::getProperty(guint propId, GValue *value,
[[maybe_unused]] GParamSpec *pspec)
{
if (!controls_acc_.contains(propId)) {
GST_WARNING("Control '%s' is not available, default value will "
"be returned",
controls::controls.at(propId)->name().c_str());
return true;
}
const ControlValue &cv = controls_acc_.get(propId);
switch (propId) {
{%- for vendor, ctrls in controls %}
{%- for ctrl in ctrls %}
case controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}: {
auto control = cv.get<{{ ctrl.type }}>();
{%- if ctrl.is_array %}
for (size_t i = 0; i < control.size(); ++i) {
GValue element = G_VALUE_INIT;
{%- if ctrl.is_rectangle %}
g_value_init(&element, GST_TYPE_PARAM_ARRAY_LIST);
gst_libcamera_gvalue_set_rectangle(&element, control[i]);
{%- else %}
g_value_init(&element, G_TYPE_{{ ctrl.gtype|upper }});
g_value_set_{{ ctrl.gtype }}(&element, control[i]);
{%- endif %}
gst_value_array_append_and_take_value(value, &element);
}
{%- else %}
{%- if ctrl.is_rectangle %}
gst_libcamera_gvalue_set_rectangle(value, control);
{%- else %}
g_value_set_{{ ctrl.gtype }}(value, control);
{%- endif %}
{%- endif %}
return true;
}
{%- endfor %}
{%- endfor %}
default:
return false;
}
}
bool GstCameraControls::setProperty(guint propId, const GValue *value,
[[maybe_unused]] GParamSpec *pspec)
{
/*
* Check whether the camera capabilities are already available.
* They might not be available if the pipeline has not started yet.
*/
if (!capabilities_.empty()) {
/* If so, check that the control is supported by the camera. */
const ControlId *cid = capabilities_.idmap().at(propId);
auto info = capabilities_.find(cid);
if (info == capabilities_.end()) {
GST_WARNING("Control '%s' is not supported by the "
"camera and will be ignored",
cid->name().c_str());
return true;
}
}
switch (propId) {
{%- for vendor, ctrls in controls %}
{%- for ctrl in ctrls %}
case controls::{{ ctrl.namespace }}{{ ctrl.name|snake_case|upper }}: {
{%- if ctrl.is_array %}
size_t size = gst_value_array_get_size(value);
{%- if ctrl.size != 0 %}
if (size != {{ ctrl.size }}) {
GST_ERROR("Incorrect array size for control "
"'{{ ctrl.name|kebab_case }}', must be of "
"size {{ ctrl.size }}");
return true;
}
{%- endif %}
std::vector<{{ ctrl.element_type }}> values(size);
for (size_t i = 0; i < size; ++i) {
const GValue *element =
gst_value_array_get_value(value, i);
{%- if ctrl.is_rectangle %}
if (gst_value_array_get_size(element) != 4) {
GST_ERROR("Rectangle in control "
"'{{ ctrl.name|kebab_case }}' at"
"index %zu must be an array of size 4",
i);
return true;
}
values[i] = gst_libcamera_gvalue_get_rectangle(element);
{%- else %}
values[i] = g_value_get_{{ ctrl.gtype }}(element);
{%- endif %}
}
{%- if ctrl.size == 0 %}
Span<const {{ ctrl.element_type }}> val(values.data(), size);
{%- else %}
Span<const {{ ctrl.element_type }}, {{ ctrl.size }}> val(values.data(), size);
{%- endif %}
{%- else %}
{%- if ctrl.is_rectangle %}
if (gst_value_array_get_size(value) != 4) {
GST_ERROR("Rectangle in control "
"'{{ ctrl.name|kebab_case }}' must be an "
"array of size 4");
return true;
}
Rectangle val = gst_libcamera_gvalue_get_rectangle(value);
{%- else %}
auto val = g_value_get_{{ ctrl.gtype }}(value);
{%- endif %}
{%- endif %}
controls_.set(controls::{{ ctrl.namespace }}{{ ctrl.name }}, val);
controls_acc_.set(controls::{{ ctrl.namespace }}{{ ctrl.name }}, val);
return true;
}
{%- endfor %}
{%- endfor %}
default:
return false;
}
}
void GstCameraControls::setCamera(const std::shared_ptr<libcamera::Camera> &cam)
{
capabilities_ = cam->controls();
/*
* Check the controls which were set before the camera capabilities were
* known. This is required because GStreamer may set properties before
* the pipeline has started and thus before the camera was known.
*/
ControlList new_controls;
for (auto control = controls_acc_.begin();
control != controls_acc_.end();
++control) {
unsigned int id = control->first;
ControlValue value = control->second;
const ControlId *cid = capabilities_.idmap().at(id);
auto info = capabilities_.find(cid);
/* Only add controls which are supported. */
if (info != capabilities_.end())
new_controls.set(id, value);
else
GST_WARNING("Control '%s' is not supported by the "
"camera and will be ignored",
cid->name().c_str());
}
controls_acc_ = new_controls;
controls_ = new_controls;
}
void GstCameraControls::applyControls(std::unique_ptr<libcamera::Request> &request)
{
request->controls().merge(controls_);
controls_.clear();
}
void GstCameraControls::readMetadata(libcamera::Request *request)
{
controls_acc_.merge(request->metadata(),
ControlList::MergePolicy::OverwriteExisting);
}