summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Dufresne <nicolas.dufresne@collabora.com>2020-01-24 13:27:04 -0500
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-03-07 01:57:45 +0200
commit2575b4916031d83bd777001c4b160e3a5c9008f9 (patch)
tree26757d782f1bc6c30dea74d716a7ea57a8cffb23
parentbd0c2df110f502afe3c868309a1ca81ad6dc3196 (diff)
gst: libcamerasrc: Implement minimal caps negotiation
This is not expected to work in every possible cases, but should be sufficient as an initial implementation. What it does is that it turns the StreamFormats into caps and queries downstream caps with that as a filter. The result is the subset of caps that can be used. We then keep the first structure in that result and fixate using the default values found in StreamConfiguration as a default in case a range is available. We then validate this configuration and turn the potentially modified configuration into caps that we push downstream. Note that we trust the order in StreamFormats as being sorted best first, but this is not currently in libcamera. A todo has been added in the head of this file as a reminder to fix that in the core. Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--src/gstreamer/gstlibcamerasrc.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 16803142..95af1414 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -6,6 +6,12 @@
* gstlibcamerasrc.cpp - GStreamer Capture Element
*/
+/**
+ * \todo libcamera UVC drivers picks the lowest possible resolution first, this
+ * should be fixed so that we get a decent resolution and framerate for the
+ * role by default.
+ */
+
#include "gstlibcamerasrc.h"
#include <vector>
@@ -25,6 +31,7 @@ GST_DEBUG_CATEGORY_STATIC(source_debug);
struct GstLibcameraSrcState {
std::unique_ptr<CameraManager> cm_;
std::shared_ptr<Camera> cam_;
+ std::unique_ptr<CameraConfiguration> config_;
std::vector<GstPad *> srcpads_;
};
@@ -133,16 +140,90 @@ gst_libcamera_src_task_enter(GstTask *task, GThread *thread, gpointer user_data)
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(user_data);
GLibRecLocker lock(&self->stream_lock);
GstLibcameraSrcState *state = self->state;
+ GstFlowReturn flow_ret = GST_FLOW_OK;
+ gint ret;
GST_DEBUG_OBJECT(self, "Streaming thread has started");
guint group_id = gst_util_group_id_next();
+ StreamRoles roles;
for (GstPad *srcpad : state->srcpads_) {
/* Create stream-id and push stream-start. */
g_autofree gchar *stream_id = gst_pad_create_stream_id(srcpad, GST_ELEMENT(self), nullptr);
GstEvent *event = gst_event_new_stream_start(stream_id);
gst_event_set_group_id(event, group_id);
gst_pad_push_event(srcpad, event);
+
+ /* Collect the streams roles for the next iteration. */
+ roles.push_back(gst_libcamera_pad_get_role(srcpad));
+ }
+
+ /* Generate the stream configurations, there should be one per pad. */
+ state->config_ = state->cam_->generateConfiguration(roles);
+ /*
+ * \todo Check if camera may increase or decrease the number of streams
+ * regardless of the number of roles.
+ */
+ g_assert(state->config_->size() == state->srcpads_.size());
+
+ for (gsize i = 0; i < state->srcpads_.size(); i++) {
+ GstPad *srcpad = state->srcpads_[i];
+ StreamConfiguration &stream_cfg = state->config_->at(i);
+
+ /* Retrieve the supported caps. */
+ g_autoptr(GstCaps) filter = gst_libcamera_stream_formats_to_caps(stream_cfg.formats());
+ g_autoptr(GstCaps) caps = gst_pad_peer_query_caps(srcpad, filter);
+ if (gst_caps_is_empty(caps)) {
+ flow_ret = GST_FLOW_NOT_NEGOTIATED;
+ break;
+ }
+
+ /* Fixate caps and configure the stream. */
+ caps = gst_caps_make_writable(caps);
+ gst_libcamera_configure_stream_from_caps(stream_cfg, caps);
+ }
+
+ if (flow_ret != GST_FLOW_OK)
+ goto done;
+
+ /* Validate the configuration. */
+ if (state->config_->validate() == CameraConfiguration::Invalid) {
+ flow_ret = GST_FLOW_NOT_NEGOTIATED;
+ goto done;
+ }
+
+ /*
+ * Regardless if it has been modified, create clean caps and push the
+ * caps event. Downstream will decide if the caps are acceptable.
+ */
+ for (gsize i = 0; i < state->srcpads_.size(); i++) {
+ GstPad *srcpad = state->srcpads_[i];
+ const StreamConfiguration &stream_cfg = state->config_->at(i);
+
+ g_autoptr(GstCaps) caps = gst_libcamera_stream_configuration_to_caps(stream_cfg);
+ if (!gst_pad_push_event(srcpad, gst_event_new_caps(caps))) {
+ flow_ret = GST_FLOW_NOT_NEGOTIATED;
+ break;
+ }
+ }
+
+ ret = state->cam_->configure(state->config_.get());
+ if (ret) {
+ GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
+ ("Failed to configure camera: %s", g_strerror(-ret)),
+ ("Camera::configure() failed with error code %i", ret));
+ gst_task_stop(task);
+ return;
+ }
+
+done:
+ switch (flow_ret) {
+ case GST_FLOW_NOT_NEGOTIATED:
+ GST_ELEMENT_FLOW_ERROR(self, flow_ret);
+ gst_task_stop(task);
+ break;
+ default:
+ break;
}
}