Skip to content

Commit 58feb69

Browse files
ndufresnepinchartl
authored andcommitted
gst: libcamerasrc: Implement selection and acquisition
This adds code to select and acquire a camera. With this, it is now possible to run a pipeline like: gst-launch-1.0 libcamerasrc ! fakesink Though no buffer will be streamed yet. In this function, we implement the change_state() virtual method to trigger actions on specific state transitions. Note that we also return GST_STATE_CHANGE_NO_PREROLL in GST_STATE_CHANGE_READY_TO_PAUSED and GST_STATE_CHANGE_PLAYING_TO_PAUSED transitions as this is required for all live sources. 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>
1 parent cfa6122 commit 58feb69

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

src/gstreamer/gstlibcamerasrc.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,29 @@
88

99
#include "gstlibcamerasrc.h"
1010

11+
#include <libcamera/camera.h>
12+
#include <libcamera/camera_manager.h>
13+
1114
#include "gstlibcamerapad.h"
1215
#include "gstlibcamera-utils.h"
1316

17+
using namespace libcamera;
18+
1419
GST_DEBUG_CATEGORY_STATIC(source_debug);
1520
#define GST_CAT_DEFAULT source_debug
1621

22+
/* Used for C++ object with destructors. */
23+
struct GstLibcameraSrcState {
24+
std::unique_ptr<CameraManager> cm_;
25+
std::shared_ptr<Camera> cam_;
26+
};
27+
1728
struct _GstLibcameraSrc {
1829
GstElement parent;
1930
GstPad *srcpad;
2031
gchar *camera_name;
32+
33+
GstLibcameraSrcState *state;
2134
};
2235

2336
enum {
@@ -41,6 +54,83 @@ GstStaticPadTemplate request_src_template = {
4154
"src_%s", GST_PAD_SRC, GST_PAD_REQUEST, TEMPLATE_CAPS
4255
};
4356

57+
static bool
58+
gst_libcamera_src_open(GstLibcameraSrc *self)
59+
{
60+
std::unique_ptr<CameraManager> cm = std::make_unique<CameraManager>();
61+
std::shared_ptr<Camera> cam;
62+
gint ret = 0;
63+
64+
GST_DEBUG_OBJECT(self, "Opening camera device ...");
65+
66+
ret = cm->start();
67+
if (ret) {
68+
GST_ELEMENT_ERROR(self, LIBRARY, INIT,
69+
("Failed listing cameras."),
70+
("libcamera::CameraMananger::start() failed: %s", g_strerror(-ret)));
71+
return false;
72+
}
73+
74+
g_autofree gchar *camera_name = nullptr;
75+
{
76+
GLibLocker lock(GST_OBJECT(self));
77+
if (self->camera_name)
78+
camera_name = g_strdup(self->camera_name);
79+
}
80+
81+
if (camera_name) {
82+
cam = cm->get(self->camera_name);
83+
if (!cam) {
84+
GST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,
85+
("Could not find a camera named '%s'.", self->camera_name),
86+
("libcamera::CameraMananger::get() returned nullptr"));
87+
return false;
88+
}
89+
} else {
90+
if (cm->cameras().empty()) {
91+
GST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,
92+
("Could not find any supported camera on this system."),
93+
("libcamera::CameraMananger::cameras() is empty"));
94+
return false;
95+
}
96+
cam = cm->cameras()[0];
97+
}
98+
99+
GST_INFO_OBJECT(self, "Using camera named '%s'", cam->name().c_str());
100+
101+
ret = cam->acquire();
102+
if (ret) {
103+
GST_ELEMENT_ERROR(self, RESOURCE, BUSY,
104+
("Camera name '%s' is already in use.", cam->name().c_str()),
105+
("libcamera::Camera::acquire() failed: %s", g_strerror(ret)));
106+
return false;
107+
}
108+
109+
/* No need to lock here, we didn't start our threads yet. */
110+
self->state->cm_ = std::move(cm);
111+
self->state->cam_ = cam;
112+
113+
return true;
114+
}
115+
116+
static void
117+
gst_libcamera_src_close(GstLibcameraSrc *self)
118+
{
119+
GstLibcameraSrcState *state = self->state;
120+
gint ret;
121+
122+
ret = state->cam_->release();
123+
if (ret) {
124+
GST_ELEMENT_WARNING(self, RESOURCE, BUSY,
125+
("Camera name '%s' is still in use.", state->cam_->name().c_str()),
126+
("libcamera::Camera.release() failed: %s", g_strerror(-ret)));
127+
}
128+
129+
state->cam_.reset();
130+
state->cm_->stop();
131+
state->cm_.reset();
132+
}
133+
44134
static void
45135
gst_libcamera_src_set_property(GObject *object, guint prop_id,
46136
const GValue *value, GParamSpec *pspec)
@@ -76,24 +166,57 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,
76166
}
77167
}
78168

169+
static GstStateChangeReturn
170+
gst_libcamera_src_change_state(GstElement *element, GstStateChange transition)
171+
{
172+
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(element);
173+
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
174+
GstElementClass *klass = GST_ELEMENT_CLASS(gst_libcamera_src_parent_class);
175+
176+
ret = klass->change_state(element, transition);
177+
if (ret == GST_STATE_CHANGE_FAILURE)
178+
return ret;
179+
180+
switch (transition) {
181+
case GST_STATE_CHANGE_NULL_TO_READY:
182+
if (!gst_libcamera_src_open(self))
183+
return GST_STATE_CHANGE_FAILURE;
184+
break;
185+
case GST_STATE_CHANGE_READY_TO_PAUSED:
186+
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
187+
ret = GST_STATE_CHANGE_NO_PREROLL;
188+
break;
189+
case GST_STATE_CHANGE_READY_TO_NULL:
190+
gst_libcamera_src_close(self);
191+
break;
192+
default:
193+
break;
194+
}
195+
196+
return ret;
197+
}
198+
79199
static void
80200
gst_libcamera_src_finalize(GObject *object)
81201
{
82202
GObjectClass *klass = G_OBJECT_CLASS(gst_libcamera_src_parent_class);
83203
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(object);
84204

85205
g_free(self->camera_name);
206+
delete self->state;
86207

87208
return klass->finalize(object);
88209
}
89210

90211
static void
91212
gst_libcamera_src_init(GstLibcameraSrc *self)
92213
{
214+
GstLibcameraSrcState *state = new GstLibcameraSrcState();
93215
GstPadTemplate *templ = gst_element_get_pad_template(GST_ELEMENT(self), "src");
94216

95217
self->srcpad = gst_pad_new_from_template(templ, "src");
96218
gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
219+
self->state = state;
97220
}
98221

99222
static void
@@ -106,6 +229,8 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
106229
object_class->get_property = gst_libcamera_src_get_property;
107230
object_class->finalize = gst_libcamera_src_finalize;
108231

232+
element_class->change_state = gst_libcamera_src_change_state;
233+
109234
gst_element_class_set_metadata(element_class,
110235
"libcamera Source", "Source/Video",
111236
"Linux Camera source using libcamera",

0 commit comments

Comments
 (0)