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>
This commit is contained in:
parent
cfa61225a4
commit
58feb69f85
1 changed files with 125 additions and 0 deletions
|
@ -8,16 +8,29 @@
|
||||||
|
|
||||||
#include "gstlibcamerasrc.h"
|
#include "gstlibcamerasrc.h"
|
||||||
|
|
||||||
|
#include <libcamera/camera.h>
|
||||||
|
#include <libcamera/camera_manager.h>
|
||||||
|
|
||||||
#include "gstlibcamerapad.h"
|
#include "gstlibcamerapad.h"
|
||||||
#include "gstlibcamera-utils.h"
|
#include "gstlibcamera-utils.h"
|
||||||
|
|
||||||
|
using namespace libcamera;
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC(source_debug);
|
GST_DEBUG_CATEGORY_STATIC(source_debug);
|
||||||
#define GST_CAT_DEFAULT source_debug
|
#define GST_CAT_DEFAULT source_debug
|
||||||
|
|
||||||
|
/* Used for C++ object with destructors. */
|
||||||
|
struct GstLibcameraSrcState {
|
||||||
|
std::unique_ptr<CameraManager> cm_;
|
||||||
|
std::shared_ptr<Camera> cam_;
|
||||||
|
};
|
||||||
|
|
||||||
struct _GstLibcameraSrc {
|
struct _GstLibcameraSrc {
|
||||||
GstElement parent;
|
GstElement parent;
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
gchar *camera_name;
|
gchar *camera_name;
|
||||||
|
|
||||||
|
GstLibcameraSrcState *state;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -41,6 +54,83 @@ GstStaticPadTemplate request_src_template = {
|
||||||
"src_%s", GST_PAD_SRC, GST_PAD_REQUEST, TEMPLATE_CAPS
|
"src_%s", GST_PAD_SRC, GST_PAD_REQUEST, TEMPLATE_CAPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gst_libcamera_src_open(GstLibcameraSrc *self)
|
||||||
|
{
|
||||||
|
std::unique_ptr<CameraManager> cm = std::make_unique<CameraManager>();
|
||||||
|
std::shared_ptr<Camera> cam;
|
||||||
|
gint ret = 0;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT(self, "Opening camera device ...");
|
||||||
|
|
||||||
|
ret = cm->start();
|
||||||
|
if (ret) {
|
||||||
|
GST_ELEMENT_ERROR(self, LIBRARY, INIT,
|
||||||
|
("Failed listing cameras."),
|
||||||
|
("libcamera::CameraMananger::start() failed: %s", g_strerror(-ret)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_autofree gchar *camera_name = nullptr;
|
||||||
|
{
|
||||||
|
GLibLocker lock(GST_OBJECT(self));
|
||||||
|
if (self->camera_name)
|
||||||
|
camera_name = g_strdup(self->camera_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (camera_name) {
|
||||||
|
cam = cm->get(self->camera_name);
|
||||||
|
if (!cam) {
|
||||||
|
GST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,
|
||||||
|
("Could not find a camera named '%s'.", self->camera_name),
|
||||||
|
("libcamera::CameraMananger::get() returned nullptr"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cm->cameras().empty()) {
|
||||||
|
GST_ELEMENT_ERROR(self, RESOURCE, NOT_FOUND,
|
||||||
|
("Could not find any supported camera on this system."),
|
||||||
|
("libcamera::CameraMananger::cameras() is empty"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cam = cm->cameras()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_INFO_OBJECT(self, "Using camera named '%s'", cam->name().c_str());
|
||||||
|
|
||||||
|
ret = cam->acquire();
|
||||||
|
if (ret) {
|
||||||
|
GST_ELEMENT_ERROR(self, RESOURCE, BUSY,
|
||||||
|
("Camera name '%s' is already in use.", cam->name().c_str()),
|
||||||
|
("libcamera::Camera::acquire() failed: %s", g_strerror(ret)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No need to lock here, we didn't start our threads yet. */
|
||||||
|
self->state->cm_ = std::move(cm);
|
||||||
|
self->state->cam_ = cam;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_libcamera_src_close(GstLibcameraSrc *self)
|
||||||
|
{
|
||||||
|
GstLibcameraSrcState *state = self->state;
|
||||||
|
gint ret;
|
||||||
|
|
||||||
|
ret = state->cam_->release();
|
||||||
|
if (ret) {
|
||||||
|
GST_ELEMENT_WARNING(self, RESOURCE, BUSY,
|
||||||
|
("Camera name '%s' is still in use.", state->cam_->name().c_str()),
|
||||||
|
("libcamera::Camera.release() failed: %s", g_strerror(-ret)));
|
||||||
|
}
|
||||||
|
|
||||||
|
state->cam_.reset();
|
||||||
|
state->cm_->stop();
|
||||||
|
state->cm_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_libcamera_src_set_property(GObject *object, guint prop_id,
|
gst_libcamera_src_set_property(GObject *object, guint prop_id,
|
||||||
const GValue *value, GParamSpec *pspec)
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
@ -76,6 +166,36 @@ gst_libcamera_src_get_property(GObject *object, guint prop_id, GValue *value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_libcamera_src_change_state(GstElement *element, GstStateChange transition)
|
||||||
|
{
|
||||||
|
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(element);
|
||||||
|
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||||
|
GstElementClass *klass = GST_ELEMENT_CLASS(gst_libcamera_src_parent_class);
|
||||||
|
|
||||||
|
ret = klass->change_state(element, transition);
|
||||||
|
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch (transition) {
|
||||||
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
|
if (!gst_libcamera_src_open(self))
|
||||||
|
return GST_STATE_CHANGE_FAILURE;
|
||||||
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
|
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||||
|
ret = GST_STATE_CHANGE_NO_PREROLL;
|
||||||
|
break;
|
||||||
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
|
gst_libcamera_src_close(self);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_libcamera_src_finalize(GObject *object)
|
gst_libcamera_src_finalize(GObject *object)
|
||||||
{
|
{
|
||||||
|
@ -83,6 +203,7 @@ gst_libcamera_src_finalize(GObject *object)
|
||||||
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(object);
|
GstLibcameraSrc *self = GST_LIBCAMERA_SRC(object);
|
||||||
|
|
||||||
g_free(self->camera_name);
|
g_free(self->camera_name);
|
||||||
|
delete self->state;
|
||||||
|
|
||||||
return klass->finalize(object);
|
return klass->finalize(object);
|
||||||
}
|
}
|
||||||
|
@ -90,10 +211,12 @@ gst_libcamera_src_finalize(GObject *object)
|
||||||
static void
|
static void
|
||||||
gst_libcamera_src_init(GstLibcameraSrc *self)
|
gst_libcamera_src_init(GstLibcameraSrc *self)
|
||||||
{
|
{
|
||||||
|
GstLibcameraSrcState *state = new GstLibcameraSrcState();
|
||||||
GstPadTemplate *templ = gst_element_get_pad_template(GST_ELEMENT(self), "src");
|
GstPadTemplate *templ = gst_element_get_pad_template(GST_ELEMENT(self), "src");
|
||||||
|
|
||||||
self->srcpad = gst_pad_new_from_template(templ, "src");
|
self->srcpad = gst_pad_new_from_template(templ, "src");
|
||||||
gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
|
gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
|
||||||
|
self->state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -106,6 +229,8 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
|
||||||
object_class->get_property = gst_libcamera_src_get_property;
|
object_class->get_property = gst_libcamera_src_get_property;
|
||||||
object_class->finalize = gst_libcamera_src_finalize;
|
object_class->finalize = gst_libcamera_src_finalize;
|
||||||
|
|
||||||
|
element_class->change_state = gst_libcamera_src_change_state;
|
||||||
|
|
||||||
gst_element_class_set_metadata(element_class,
|
gst_element_class_set_metadata(element_class,
|
||||||
"libcamera Source", "Source/Video",
|
"libcamera Source", "Source/Video",
|
||||||
"Linux Camera source using libcamera",
|
"Linux Camera source using libcamera",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue