diff options
Diffstat (limited to 'src/gstreamer')
-rw-r--r-- | src/gstreamer/gstlibcamera.cpp | 2 | ||||
-rw-r--r-- | src/gstreamer/gstlibcameraallocator.cpp | 8 | ||||
-rw-r--r-- | src/gstreamer/gstlibcameraallocator.h | 4 | ||||
-rw-r--r-- | src/gstreamer/gstlibcamerapad.cpp | 2 | ||||
-rw-r--r-- | src/gstreamer/gstlibcamerapool.cpp | 6 | ||||
-rw-r--r-- | src/gstreamer/gstlibcameraprovider.cpp | 10 | ||||
-rw-r--r-- | src/gstreamer/gstlibcamerasrc.cpp | 109 | ||||
-rw-r--r-- | src/gstreamer/meson.build | 54 |
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')), +) |