8
8
9
9
#include " gstlibcamerasrc.h"
10
10
11
+ #include < libcamera/camera.h>
12
+ #include < libcamera/camera_manager.h>
13
+
11
14
#include " gstlibcamerapad.h"
12
15
#include " gstlibcamera-utils.h"
13
16
17
+ using namespace libcamera ;
18
+
14
19
GST_DEBUG_CATEGORY_STATIC (source_debug);
15
20
#define GST_CAT_DEFAULT source_debug
16
21
22
+ /* Used for C++ object with destructors. */
23
+ struct GstLibcameraSrcState {
24
+ std::unique_ptr<CameraManager> cm_;
25
+ std::shared_ptr<Camera> cam_;
26
+ };
27
+
17
28
struct _GstLibcameraSrc {
18
29
GstElement parent;
19
30
GstPad *srcpad;
20
31
gchar *camera_name;
32
+
33
+ GstLibcameraSrcState *state;
21
34
};
22
35
23
36
enum {
@@ -41,6 +54,83 @@ GstStaticPadTemplate request_src_template = {
41
54
" src_%s" , GST_PAD_SRC, GST_PAD_REQUEST, TEMPLATE_CAPS
42
55
};
43
56
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
+
44
134
static void
45
135
gst_libcamera_src_set_property (GObject *object, guint prop_id,
46
136
const GValue *value, GParamSpec *pspec)
@@ -76,24 +166,57 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,
76
166
}
77
167
}
78
168
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
+
79
199
static void
80
200
gst_libcamera_src_finalize (GObject *object)
81
201
{
82
202
GObjectClass *klass = G_OBJECT_CLASS (gst_libcamera_src_parent_class);
83
203
GstLibcameraSrc *self = GST_LIBCAMERA_SRC (object);
84
204
85
205
g_free (self->camera_name );
206
+ delete self->state ;
86
207
87
208
return klass->finalize (object);
88
209
}
89
210
90
211
static void
91
212
gst_libcamera_src_init (GstLibcameraSrc *self)
92
213
{
214
+ GstLibcameraSrcState *state = new GstLibcameraSrcState ();
93
215
GstPadTemplate *templ = gst_element_get_pad_template (GST_ELEMENT (self), " src" );
94
216
95
217
self->srcpad = gst_pad_new_from_template (templ, " src" );
96
218
gst_element_add_pad (GST_ELEMENT (self), self->srcpad );
219
+ self->state = state;
97
220
}
98
221
99
222
static void
@@ -106,6 +229,8 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
106
229
object_class->get_property = gst_libcamera_src_get_property;
107
230
object_class->finalize = gst_libcamera_src_finalize;
108
231
232
+ element_class->change_state = gst_libcamera_src_change_state;
233
+
109
234
gst_element_class_set_metadata (element_class,
110
235
" libcamera Source" , " Source/Video" ,
111
236
" Linux Camera source using libcamera" ,
0 commit comments