summaryrefslogtreecommitdiff
path: root/src/gstreamer
diff options
context:
space:
mode:
Diffstat (limited to 'src/gstreamer')
-rw-r--r--src/gstreamer/gstlibcamera.cpp2
-rw-r--r--src/gstreamer/gstlibcameraallocator.cpp8
-rw-r--r--src/gstreamer/gstlibcameraallocator.h4
-rw-r--r--src/gstreamer/gstlibcamerapad.cpp2
-rw-r--r--src/gstreamer/gstlibcamerapool.cpp6
-rw-r--r--src/gstreamer/gstlibcameraprovider.cpp10
-rw-r--r--src/gstreamer/gstlibcamerasrc.cpp109
-rw-r--r--src/gstreamer/meson.build54
8 files changed, 137 insertions, 58 deletions
diff --git a/src/gstreamer/gstlibcamera.cpp b/src/gstreamer/gstlibcamera.cpp
index 81c7bb19..52388b5e 100644
--- a/src/gstreamer/gstlibcamera.cpp
+++ b/src/gstreamer/gstlibcamera.cpp
@@ -24,4 +24,4 @@ plugin_init(GstPlugin *plugin)
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR,
libcamera, "libcamera capture plugin",
- plugin_init, VERSION, "LGPL", PACKAGE, "https://libcamera.org");
+ plugin_init, VERSION, "LGPL", PACKAGE, "https://libcamera.org")
diff --git a/src/gstreamer/gstlibcameraallocator.cpp b/src/gstreamer/gstlibcameraallocator.cpp
index 78ded402..7bd8ba2d 100644
--- a/src/gstreamer/gstlibcameraallocator.cpp
+++ b/src/gstreamer/gstlibcameraallocator.cpp
@@ -101,7 +101,7 @@ struct _GstLibcameraAllocator {
};
G_DEFINE_TYPE(GstLibcameraAllocator, gst_libcamera_allocator,
- GST_TYPE_DMABUF_ALLOCATOR);
+ GST_TYPE_DMABUF_ALLOCATOR)
static gboolean
gst_libcamera_allocator_release(GstMiniObject *mini_object)
@@ -183,13 +183,15 @@ gst_libcamera_allocator_class_init(GstLibcameraAllocatorClass *klass)
}
GstLibcameraAllocator *
-gst_libcamera_allocator_new(std::shared_ptr<Camera> camera)
+gst_libcamera_allocator_new(std::shared_ptr<Camera> camera,
+ CameraConfiguration *config_)
{
auto *self = GST_LIBCAMERA_ALLOCATOR(g_object_new(GST_TYPE_LIBCAMERA_ALLOCATOR,
nullptr));
self->fb_allocator = new FrameBufferAllocator(camera);
- for (Stream *stream : camera->streams()) {
+ for (StreamConfiguration &streamCfg : *config_) {
+ Stream *stream = streamCfg.stream();
gint ret;
ret = self->fb_allocator->allocate(stream);
diff --git a/src/gstreamer/gstlibcameraallocator.h b/src/gstreamer/gstlibcameraallocator.h
index befdcad6..0dbd00d0 100644
--- a/src/gstreamer/gstlibcameraallocator.h
+++ b/src/gstreamer/gstlibcameraallocator.h
@@ -12,13 +12,15 @@
#include <gst/gst.h>
#include <gst/allocators/allocators.h>
+#include <libcamera/camera.h>
#include <libcamera/stream.h>
#define GST_TYPE_LIBCAMERA_ALLOCATOR gst_libcamera_allocator_get_type()
G_DECLARE_FINAL_TYPE(GstLibcameraAllocator, gst_libcamera_allocator,
GST_LIBCAMERA, ALLOCATOR, GstDmaBufAllocator)
-GstLibcameraAllocator *gst_libcamera_allocator_new(std::shared_ptr<libcamera::Camera> camera);
+GstLibcameraAllocator *gst_libcamera_allocator_new(std::shared_ptr<libcamera::Camera> camera,
+ libcamera::CameraConfiguration *config_);
bool gst_libcamera_allocator_prepare_buffer(GstLibcameraAllocator *self,
libcamera::Stream *stream,
diff --git a/src/gstreamer/gstlibcamerapad.cpp b/src/gstreamer/gstlibcamerapad.cpp
index 9f3e2be5..c00e81c8 100644
--- a/src/gstreamer/gstlibcamerapad.cpp
+++ b/src/gstreamer/gstlibcamerapad.cpp
@@ -27,7 +27,7 @@ enum {
PROP_STREAM_ROLE
};
-G_DEFINE_TYPE(GstLibcameraPad, gst_libcamera_pad, GST_TYPE_PAD);
+G_DEFINE_TYPE(GstLibcameraPad, gst_libcamera_pad, GST_TYPE_PAD)
static void
gst_libcamera_pad_set_property(GObject *object, guint prop_id,
diff --git a/src/gstreamer/gstlibcamerapool.cpp b/src/gstreamer/gstlibcamerapool.cpp
index b756ee35..1fde4213 100644
--- a/src/gstreamer/gstlibcamerapool.cpp
+++ b/src/gstreamer/gstlibcamerapool.cpp
@@ -29,7 +29,7 @@ struct _GstLibcameraPool {
Stream *stream;
};
-G_DEFINE_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_TYPE_BUFFER_POOL);
+G_DEFINE_TYPE(GstLibcameraPool, gst_libcamera_pool, GST_TYPE_BUFFER_POOL)
static GstFlowReturn
gst_libcamera_pool_acquire_buffer(GstBufferPool *pool, GstBuffer **buffer,
@@ -40,8 +40,10 @@ gst_libcamera_pool_acquire_buffer(GstBufferPool *pool, GstBuffer **buffer,
if (!buf)
return GST_FLOW_ERROR;
- if (!gst_libcamera_allocator_prepare_buffer(self->allocator, self->stream, buf))
+ if (!gst_libcamera_allocator_prepare_buffer(self->allocator, self->stream, buf)) {
+ gst_atomic_queue_push(self->queue, buf);
return GST_FLOW_ERROR;
+ }
*buffer = buf;
return GST_FLOW_OK;
diff --git a/src/gstreamer/gstlibcameraprovider.cpp b/src/gstreamer/gstlibcameraprovider.cpp
index cd850d81..29da6c32 100644
--- a/src/gstreamer/gstlibcameraprovider.cpp
+++ b/src/gstreamer/gstlibcameraprovider.cpp
@@ -35,14 +35,14 @@ enum {
#define GST_TYPE_LIBCAMERA_DEVICE gst_libcamera_device_get_type()
G_DECLARE_FINAL_TYPE(GstLibcameraDevice, gst_libcamera_device,
- GST_LIBCAMERA, DEVICE, GstDevice);
+ GST_LIBCAMERA, DEVICE, GstDevice)
struct _GstLibcameraDevice {
GstDevice parent;
gchar *name;
};
-G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE);
+G_DEFINE_TYPE(GstLibcameraDevice, gst_libcamera_device, GST_TYPE_DEVICE)
static GstElement *
gst_libcamera_device_create_element(GstDevice *device, const gchar *name)
@@ -101,7 +101,7 @@ gst_libcamera_device_finalize(GObject *object)
g_free(self->name);
- G_OBJECT_GET_CLASS(klass)->finalize(object);
+ G_OBJECT_CLASS(klass)->finalize(object);
}
static void
@@ -164,7 +164,7 @@ struct _GstLibcameraProvider {
G_DEFINE_TYPE_WITH_CODE(GstLibcameraProvider, gst_libcamera_provider,
GST_TYPE_DEVICE_PROVIDER,
GST_DEBUG_CATEGORY_INIT(provider_debug, "libcamera-provider", 0,
- "libcamera Device Provider"));
+ "libcamera Device Provider"))
static GList *
gst_libcamera_provider_probe(GstDeviceProvider *provider)
@@ -218,7 +218,7 @@ gst_libcamera_provider_finalize(GObject *object)
delete self->cm;
- return G_OBJECT_GET_CLASS(klass)->finalize(object);
+ return G_OBJECT_CLASS(klass)->finalize(object);
}
static void
diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 1bfc2e2f..ea53c2b5 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -52,19 +52,18 @@ GST_DEBUG_CATEGORY_STATIC(source_debug);
#define GST_CAT_DEFAULT source_debug
struct RequestWrap {
- RequestWrap(Request *request);
+ RequestWrap(std::unique_ptr<Request> request);
~RequestWrap();
void attachBuffer(GstBuffer *buffer);
GstBuffer *detachBuffer(Stream *stream);
- /* For ptr comparison only. */
- Request *request_;
+ std::unique_ptr<Request> request_;
std::map<Stream *, GstBuffer *> buffers_;
};
-RequestWrap::RequestWrap(Request *request)
- : request_(request)
+RequestWrap::RequestWrap(std::unique_ptr<Request> request)
+ : request_(std::move(request))
{
}
@@ -138,7 +137,7 @@ enum {
G_DEFINE_TYPE_WITH_CODE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT,
GST_DEBUG_CATEGORY_INIT(source_debug, "libcamerasrc", 0,
- "libcamera Source"));
+ "libcamera Source"))
#define TEMPLATE_CAPS GST_STATIC_CAPS("video/x-raw; image/jpeg")
@@ -162,7 +161,7 @@ GstLibcameraSrcState::requestCompleted(Request *request)
std::unique_ptr<RequestWrap> wrap = std::move(requests_.front());
requests_.pop();
- g_return_if_fail(wrap->request_ == request);
+ g_return_if_fail(wrap->request_.get() == request);
if ((request->status() == Request::RequestCancelled)) {
GST_DEBUG_OBJECT(src_, "Request was cancelled");
@@ -266,8 +265,19 @@ gst_libcamera_src_task_run(gpointer user_data)
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(user_data);
GstLibcameraSrcState *state = self->state;
- Request *request = state->cam_->createRequest();
- auto wrap = std::make_unique<RequestWrap>(request);
+ std::unique_ptr<Request> request = state->cam_->createRequest();
+ if (!request) {
+ GST_ELEMENT_ERROR(self, RESOURCE, NO_SPACE_LEFT,
+ ("Failed to allocate request for camera '%s'.",
+ state->cam_->id().c_str()),
+ ("libcamera::Camera::createRequest() failed"));
+ gst_task_stop(self->task);
+ return;
+ }
+
+ std::unique_ptr<RequestWrap> wrap =
+ std::make_unique<RequestWrap>(std::move(request));
+
for (GstPad *srcpad : state->srcpads_) {
GstLibcameraPool *pool = gst_libcamera_pad_get_pool(srcpad);
GstBuffer *buffer;
@@ -277,22 +287,23 @@ gst_libcamera_src_task_run(gpointer user_data)
&buffer, nullptr);
if (ret != GST_FLOW_OK) {
/*
- * RequestWrap does not take ownership, and we won't be
- * queueing this one due to lack of buffers.
+ * RequestWrap has ownership of the rquest, and we
+ * won't be queueing this one due to lack of buffers.
*/
- delete request;
- request = nullptr;
+ wrap.release();
break;
}
wrap->attachBuffer(buffer);
}
- if (request) {
+ if (wrap) {
GLibLocker lock(GST_OBJECT(self));
GST_TRACE_OBJECT(self, "Requesting buffers");
- state->cam_->queueRequest(request);
+ state->cam_->queueRequest(wrap->request_.get());
state->requests_.push(std::move(wrap));
+
+ /* The RequestWrap will be deleted in the completion handler. */
}
GstFlowReturn ret = GST_FLOW_OK;
@@ -350,10 +361,12 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
GST_DEBUG_OBJECT(self, "Streaming thread has started");
guint group_id = gst_util_group_id_next();
+ gint stream_id_num = 0;
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);
+ g_autofree gchar *stream_id_intermediate = g_strdup_printf("%i%i", group_id, stream_id_num++);
+ g_autofree gchar *stream_id = gst_pad_create_stream_id(srcpad, GST_ELEMENT(self), stream_id_intermediate);
GstEvent *event = gst_event_new_stream_start(stream_id);
gst_event_set_group_id(event, group_id);
gst_pad_push_event(srcpad, event);
@@ -364,10 +377,13 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
/* 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.
- */
+ if (state->config_ == nullptr) {
+ GST_ELEMENT_ERROR(self, RESOURCE, SETTINGS,
+ ("Failed to generate camera configuration from roles"),
+ ("Camera::generateConfiguration() returned nullptr"));
+ gst_task_stop(task);
+ return;
+ }
g_assert(state->config_->size() == state->srcpads_.size());
for (gsize i = 0; i < state->srcpads_.size(); i++) {
@@ -425,7 +441,7 @@ gst_libcamera_src_task_enter(GstTask *task, [[maybe_unused]] GThread *thread,
return;
}
- self->allocator = gst_libcamera_allocator_new(state->cam_);
+ self->allocator = gst_libcamera_allocator_new(state->cam_, state->config_.get());
if (!self->allocator) {
GST_ELEMENT_ERROR(self, RESOURCE, NO_SPACE_LEFT,
("Failed to allocate memory"),
@@ -495,6 +511,8 @@ gst_libcamera_src_close(GstLibcameraSrc *self)
GST_DEBUG_OBJECT(self, "Releasing resources");
+ state->config_.reset();
+
ret = state->cam_->release();
if (ret) {
GST_ELEMENT_WARNING(self, RESOURCE, BUSY,
@@ -624,6 +642,53 @@ gst_libcamera_src_init(GstLibcameraSrc *self)
self->state = state;
}
+static GstPad *
+gst_libcamera_src_request_new_pad(GstElement *element, GstPadTemplate *templ,
+ const gchar *name, [[maybe_unused]] const GstCaps *caps)
+{
+ GstLibcameraSrc *self = GST_LIBCAMERA_SRC(element);
+ g_autoptr(GstPad) pad = NULL;
+
+ GST_DEBUG_OBJECT(self, "new request pad created");
+
+ pad = gst_pad_new_from_template(templ, name);
+ g_object_ref_sink(pad);
+
+ if (gst_element_add_pad(element, pad)) {
+ GLibLocker lock(GST_OBJECT(self));
+ self->state->srcpads_.push_back(reinterpret_cast<GstPad *>(g_object_ref(pad)));
+ } else {
+ GST_ELEMENT_ERROR(element, STREAM, FAILED,
+ ("Internal data stream error."),
+ ("Could not add pad to element"));
+ return NULL;
+ }
+
+ return reinterpret_cast<GstPad *>(g_steal_pointer(&pad));
+}
+
+static void
+gst_libcamera_src_release_pad(GstElement *element, GstPad *pad)
+{
+ GstLibcameraSrc *self = GST_LIBCAMERA_SRC(element);
+
+ GST_DEBUG_OBJECT(self, "Pad %" GST_PTR_FORMAT " being released", pad);
+
+ {
+ GLibLocker lock(GST_OBJECT(self));
+ std::vector<GstPad *> &pads = self->state->srcpads_;
+ auto begin_iterator = pads.begin();
+ auto end_iterator = pads.end();
+ auto pad_iterator = std::find(begin_iterator, end_iterator, pad);
+
+ if (pad_iterator != end_iterator) {
+ g_object_unref(*pad_iterator);
+ pads.erase(pad_iterator);
+ }
+ }
+ gst_element_remove_pad(element, pad);
+}
+
static void
gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
{
@@ -634,6 +699,8 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
object_class->get_property = gst_libcamera_src_get_property;
object_class->finalize = gst_libcamera_src_finalize;
+ element_class->request_new_pad = gst_libcamera_src_request_new_pad;
+ element_class->release_pad = gst_libcamera_src_release_pad;
element_class->change_state = gst_libcamera_src_change_state;
gst_element_class_set_metadata(element_class,
diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build
index c9f0c13d..77c79140 100644
--- a/src/gstreamer/meson.build
+++ b/src/gstreamer/meson.build
@@ -1,5 +1,20 @@
# SPDX-License-Identifier: CC0-1.0
+glib_dep = dependency('glib-2.0', required : get_option('gstreamer'))
+
+gst_dep_version = '>=1.14.0'
+gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_dep_version,
+ required : get_option('gstreamer'))
+gstallocator_dep = dependency('gstreamer-allocators-1.0', version : gst_dep_version,
+ required : get_option('gstreamer'))
+
+if not glib_dep.found() or not gstvideo_dep.found() or not gstallocator_dep.found()
+ gst_enabled = false
+ subdir_done()
+endif
+
+gst_enabled = true
+
libcamera_gst_sources = [
'gstlibcamera-utils.cpp',
'gstlibcamera.cpp',
@@ -13,30 +28,21 @@ libcamera_gst_sources = [
libcamera_gst_cpp_args = [
'-DVERSION="@0@"'.format(libcamera_git_version),
'-DPACKAGE="@0@"'.format(meson.project_name()),
+ '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_40',
]
-glib_dep = dependency('glib-2.0', required : get_option('gstreamer'))
-
-gst_dep_version = '>=1.14.0'
-gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_dep_version,
- required : get_option('gstreamer'))
-gstallocator_dep = dependency('gstreamer-allocators-1.0', version : gst_dep_version,
- required : get_option('gstreamer'))
-
-if glib_dep.found() and gstvideo_dep.found() and gstallocator_dep.found()
- # The G_DECLARE_FINAL_TYPE macro creates static inline functions that were
- # not marked as possibly unused prior to GLib v2.63.0. This causes clang to
- # complain about the ones we are not using. Silence the -Wunused-function
- # warning in that case.
- if cc.get_id() == 'clang' and glib_dep.version().version_compare('<2.63.0')
- libcamera_gst_cpp_args += [ '-Wno-unused-function' ]
- endif
-
- libcamera_gst = shared_library('gstlibcamera',
- libcamera_gst_sources,
- cpp_args : libcamera_gst_cpp_args,
- dependencies : [libcamera_dep, gstvideo_dep, gstallocator_dep],
- install: true,
- install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')),
- )
+# The G_DECLARE_FINAL_TYPE macro creates static inline functions that were
+# not marked as possibly unused prior to GLib v2.63.0. This causes clang to
+# complain about the ones we are not using. Silence the -Wunused-function
+# warning in that case.
+if cc.get_id() == 'clang' and glib_dep.version().version_compare('<2.63.0')
+ libcamera_gst_cpp_args += ['-Wno-unused-function']
endif
+
+libcamera_gst = shared_library('gstlibcamera',
+ libcamera_gst_sources,
+ cpp_args : libcamera_gst_cpp_args,
+ dependencies : [libcamera_public, gstvideo_dep, gstallocator_dep],
+ install: true,
+ install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir')),
+)