mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-10-14 20:02:38 +00:00
Add more generic gst source manager object
Use device manager to add/remove all video providers dynamically, remove v4l2 specific code. Get the client proxy from subscribe instead of waiting for the subscription callback. This way we can actually make an error on failure. Clean up the objects when the server disappears. Remove subscription from the server, we don't need it. Install server objects in bus_acquired.
This commit is contained in:
parent
e24398fe8c
commit
f50d1548d5
|
@ -190,7 +190,8 @@ libpulsevideocore_@PV_MAJORMINOR@_la_SOURCES = \
|
|||
server/pv-source.c server/pv-source.h \
|
||||
server/pv-client-source.c server/pv-client-source.h \
|
||||
server/pv-source-output.c server/pv-source-output.h \
|
||||
modules/v4l2/pv-v4l2-source.c
|
||||
modules/gst/pv-gst-manager.c \
|
||||
modules/gst/pv-gst-source.c
|
||||
|
||||
libpulsevideocore_@PV_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(SERVER_CFLAGS)
|
||||
libpulsevideocore_@PV_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
|
||||
|
|
|
@ -307,6 +307,33 @@ context_set_state (PvContext *context, PvContextState state)
|
|||
g_object_notify (G_OBJECT (context), "state");
|
||||
}
|
||||
}
|
||||
static void
|
||||
on_client_proxy (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvContext *context = user_data;
|
||||
PvContextPrivate *priv = context->priv;
|
||||
GError *error = NULL;
|
||||
|
||||
priv->client = pv_subscribe_get_proxy_finish (priv->subscribe,
|
||||
res,
|
||||
&error);
|
||||
if (priv->client == NULL)
|
||||
goto client_failed;
|
||||
|
||||
context_set_state (context, PV_CONTEXT_STATE_READY);
|
||||
|
||||
return;
|
||||
|
||||
client_failed:
|
||||
{
|
||||
priv->error = error;
|
||||
context_set_state (context, PV_STREAM_STATE_ERROR);
|
||||
g_error ("failed to get client proxy: %s", error->message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_client_connected (GObject *source_object,
|
||||
|
@ -330,6 +357,14 @@ on_client_connected (GObject *source_object,
|
|||
|
||||
g_variant_get (ret, "(o)", &priv->client_path);
|
||||
g_variant_unref (ret);
|
||||
|
||||
pv_subscribe_get_proxy (priv->subscribe,
|
||||
PV_DBUS_SERVICE,
|
||||
priv->client_path,
|
||||
"org.pulsevideo.Client1",
|
||||
NULL,
|
||||
on_client_proxy,
|
||||
context);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -372,10 +407,6 @@ subscription_cb (PvSubscribe *subscribe,
|
|||
break;
|
||||
|
||||
case PV_SUBSCRIPTION_FLAGS_CLIENT:
|
||||
if (g_strcmp0 (g_dbus_proxy_get_object_path (object), priv->client_path) == 0) {
|
||||
priv->client = object;
|
||||
context_set_state (context, PV_CONTEXT_STATE_READY);
|
||||
}
|
||||
break;
|
||||
|
||||
case PV_SUBSCRIPTION_FLAGS_SOURCE:
|
||||
|
|
|
@ -49,7 +49,7 @@ pv_context_list_source_info (PvContext *context,
|
|||
GDBusProxy *proxy = walk->data;
|
||||
PvSourceInfo info;
|
||||
|
||||
info.name = "v4l2";
|
||||
info.name = "gst";
|
||||
|
||||
cb (context, &info, user_data);
|
||||
}
|
||||
|
|
|
@ -134,17 +134,28 @@ object_data_free (PvObjectData *data)
|
|||
static void
|
||||
remove_data (PvSubscribe *subscribe, PvObjectData *data)
|
||||
{
|
||||
PvSubscribePrivate *priv = subscribe->priv;
|
||||
|
||||
if (data->pending) {
|
||||
data->removed = TRUE;
|
||||
} else {
|
||||
priv->objects = g_list_remove (priv->objects, data);
|
||||
notify_event (subscribe, data, PV_SUBSCRIPTION_EVENT_REMOVE);
|
||||
object_data_free (data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remove_all_data (PvSubscribe *subscribe)
|
||||
{
|
||||
PvSubscribePrivate *priv = subscribe->priv;
|
||||
GList *walk;
|
||||
|
||||
for (walk = priv->objects; walk; walk = g_list_next (walk)) {
|
||||
PvObjectData *data = walk->data;
|
||||
remove_data (subscribe, data);
|
||||
}
|
||||
g_list_free (priv->objects);
|
||||
priv->objects = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
on_proxy_created (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
|
@ -185,9 +196,11 @@ on_proxy_created (GObject *source_object,
|
|||
if (--priv->pending_proxies == 0)
|
||||
subscription_set_state (subscribe, PV_SUBSCRIPTION_STATE_READY);
|
||||
|
||||
if (data->removed)
|
||||
if (data->removed) {
|
||||
priv->objects = g_list_remove (priv->objects, data);
|
||||
remove_data (subscribe, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
|
@ -233,6 +246,7 @@ remove_interface (PvSubscribe *subscribe,
|
|||
|
||||
if (g_strcmp0 (data->object_path, object_path) == 0 &&
|
||||
g_strcmp0 (data->interface_name, interface_name) == 0) {
|
||||
priv->objects = g_list_remove (priv->objects, data);
|
||||
remove_data (subscribe, data);
|
||||
break;
|
||||
}
|
||||
|
@ -364,6 +378,7 @@ manager_proxy_appeared (PvSubscribe *subscribe)
|
|||
static void
|
||||
manager_proxy_disappeared (PvSubscribe *subscribe)
|
||||
{
|
||||
remove_all_data (subscribe);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include <client/pulsevideo.h>
|
||||
#include <server/pv-daemon.h>
|
||||
#include <modules/v4l2/pv-v4l2-source.h>
|
||||
#include <modules/gst/pv-gst-manager.h>
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
|
@ -36,7 +36,7 @@ main (gint argc, gchar *argv[])
|
|||
|
||||
daemon = pv_daemon_new ();
|
||||
|
||||
pv_v4l2_source_new (daemon);
|
||||
pv_gst_manager_new (daemon);
|
||||
pv_daemon_start (daemon);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
|
229
src/modules/gst/pv-gst-manager.c
Normal file
229
src/modules/gst/pv-gst-manager.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
/* Pulsevideo
|
||||
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "pv-gst-manager.h"
|
||||
#include "pv-gst-source.h"
|
||||
|
||||
#define PV_GST_MANAGER_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_GST_MANAGER, PvGstManagerPrivate))
|
||||
|
||||
struct _PvGstManagerPrivate
|
||||
{
|
||||
PvDaemon *daemon;
|
||||
|
||||
GstDeviceMonitor *monitor;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DAEMON
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PvGstManager, pv_gst_manager, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
device_added (PvGstManager *manager, GstDevice *device)
|
||||
{
|
||||
PvGstManagerPrivate *priv = manager->priv;
|
||||
gchar *name;
|
||||
GstElement *element;
|
||||
PvSource *source;
|
||||
|
||||
name = gst_device_get_display_name (device);
|
||||
g_print("Device added: %s\n", name);
|
||||
|
||||
element = gst_device_create_element (device, NULL);
|
||||
source = pv_gst_source_new (priv->daemon, name, element);
|
||||
g_object_set_data (G_OBJECT (device), "PvSource", source);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed (PvGstManager *manager, GstDevice *device)
|
||||
{
|
||||
gchar *name;
|
||||
PvSource *source;
|
||||
|
||||
name = gst_device_get_display_name (device);
|
||||
g_print("Device removed: %s\n", name);
|
||||
source = g_object_steal_data (G_OBJECT (device), "PvSource");
|
||||
g_object_unref (source);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bus_handler (GstBus * bus, GstMessage * message, gpointer user_data)
|
||||
{
|
||||
PvGstManager *manager = user_data;
|
||||
PvGstManagerPrivate *priv = manager->priv;
|
||||
GstDevice *device;
|
||||
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_DEVICE_ADDED:
|
||||
gst_message_parse_device_added (message, &device);
|
||||
device_added (manager, device);
|
||||
break;
|
||||
case GST_MESSAGE_DEVICE_REMOVED:
|
||||
gst_message_parse_device_removed (message, &device);
|
||||
device_removed (manager, device);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_monitor (PvGstManager *manager)
|
||||
{
|
||||
PvGstManagerPrivate *priv = manager->priv;
|
||||
GstBus *bus;
|
||||
GList *devices;
|
||||
|
||||
priv->monitor = gst_device_monitor_new ();
|
||||
|
||||
bus = gst_device_monitor_get_bus (priv->monitor);
|
||||
gst_bus_add_watch (bus, bus_handler, manager);
|
||||
gst_object_unref (bus);
|
||||
|
||||
gst_device_monitor_add_filter (priv->monitor, "Video/Source", NULL);
|
||||
|
||||
gst_device_monitor_start (priv->monitor);
|
||||
|
||||
devices = gst_device_monitor_get_devices (priv->monitor);
|
||||
while (devices != NULL) {
|
||||
GstDevice *device = devices->data;
|
||||
|
||||
device_added (manager, device);
|
||||
gst_object_unref (device);
|
||||
devices = g_list_remove_link (devices, devices);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stop_monitor (PvGstManager *manager)
|
||||
{
|
||||
PvGstManagerPrivate *priv = manager->priv;
|
||||
|
||||
if (priv->monitor) {
|
||||
gst_device_monitor_stop (priv->monitor);
|
||||
g_object_unref (priv->monitor);
|
||||
priv->monitor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_gst_manager_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvGstManager *manager = PV_GST_MANAGER (object);
|
||||
PvGstManagerPrivate *priv = manager->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
g_value_set_object (value, priv->daemon);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_gst_manager_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvGstManager *manager = PV_GST_MANAGER (object);
|
||||
PvGstManagerPrivate *priv = manager->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DAEMON:
|
||||
priv->daemon = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_manager_constructed (GObject * object)
|
||||
{
|
||||
PvGstManager *manager = PV_GST_MANAGER (object);
|
||||
|
||||
start_monitor (manager);
|
||||
|
||||
G_OBJECT_CLASS (pv_gst_manager_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_manager_finalize (GObject * object)
|
||||
{
|
||||
PvGstManager *manager = PV_GST_MANAGER (object);
|
||||
|
||||
stop_monitor (manager);
|
||||
|
||||
G_OBJECT_CLASS (pv_gst_manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_gst_manager_class_init (PvGstManagerClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvGstManagerPrivate));
|
||||
|
||||
gobject_class->constructed = gst_manager_constructed;
|
||||
gobject_class->finalize = gst_manager_finalize;
|
||||
gobject_class->set_property = pv_gst_manager_set_property;
|
||||
gobject_class->get_property = pv_gst_manager_get_property;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DAEMON,
|
||||
g_param_spec_object ("daemon",
|
||||
"Daemon",
|
||||
"The daemon",
|
||||
PV_TYPE_DAEMON,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
pv_gst_manager_init (PvGstManager * manager)
|
||||
{
|
||||
manager->priv = PV_GST_MANAGER_GET_PRIVATE (manager);
|
||||
}
|
||||
|
||||
PvGstManager *
|
||||
pv_gst_manager_new (PvDaemon *daemon)
|
||||
{
|
||||
return g_object_new (PV_TYPE_GST_MANAGER, "daemon", daemon, NULL);
|
||||
}
|
60
src/modules/gst/pv-gst-manager.h
Normal file
60
src/modules/gst/pv-gst-manager.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* Pulsevideo
|
||||
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __PV_GST_MANAGER_H__
|
||||
#define __PV_GST_MANAGER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <client/pulsevideo.h>
|
||||
#include <server/pv-daemon.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_GST_MANAGER (pv_gst_manager_get_type ())
|
||||
#define PV_IS_GST_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_GST_MANAGER))
|
||||
#define PV_IS_GST_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_GST_MANAGER))
|
||||
#define PV_GST_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_GST_MANAGER, PvGstManagerClass))
|
||||
#define PV_GST_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_GST_MANAGER, PvGstManager))
|
||||
#define PV_GST_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_GST_MANAGER, PvGstManagerClass))
|
||||
#define PV_GST_MANAGER_CAST(obj) ((PvGstManager*)(obj))
|
||||
#define PV_GST_MANAGER_CLASS_CAST(klass) ((PvGstManagerClass*)(klass))
|
||||
|
||||
typedef struct _PvGstManager PvGstManager;
|
||||
typedef struct _PvGstManagerClass PvGstManagerClass;
|
||||
typedef struct _PvGstManagerPrivate PvGstManagerPrivate;
|
||||
|
||||
struct _PvGstManager {
|
||||
GObject object;
|
||||
|
||||
PvGstManagerPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PvGstManagerClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType pv_gst_manager_get_type (void);
|
||||
|
||||
PvGstManager * pv_gst_manager_new (PvDaemon *daemon);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_GST_MANAGER_H__ */
|
||||
|
|
@ -21,28 +21,33 @@
|
|||
#include <gst/gst.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "pv-v4l2-source.h"
|
||||
#include "pv-gst-source.h"
|
||||
|
||||
#define PV_V4L2_SOURCE_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_V4L2_SOURCE, PvV4l2SourcePrivate))
|
||||
#define PV_GST_SOURCE_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_GST_SOURCE, PvGstSourcePrivate))
|
||||
|
||||
struct _PvV4l2SourcePrivate
|
||||
struct _PvGstSourcePrivate
|
||||
{
|
||||
GstElement *pipeline;
|
||||
GstElement *src;
|
||||
GstElement *element;
|
||||
GstElement *filter;
|
||||
GstElement *sink;
|
||||
|
||||
GstCaps *possible_formats;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PvV4l2Source, pv_v4l2_source, PV_TYPE_SOURCE);
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ELEMENT,
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PvGstSource, pv_gst_source, PV_TYPE_SOURCE);
|
||||
|
||||
static gboolean
|
||||
bus_handler (GstBus * bus, GstMessage * message, gpointer user_data)
|
||||
{
|
||||
PvSource *source = user_data;
|
||||
PvV4l2SourcePrivate *priv = PV_V4L2_SOURCE (source)->priv;
|
||||
PvGstSourcePrivate *priv = PV_GST_SOURCE (source)->priv;
|
||||
|
||||
switch (GST_MESSAGE_TYPE (message)) {
|
||||
case GST_MESSAGE_ERROR:
|
||||
|
@ -65,26 +70,34 @@ bus_handler (GstBus * bus, GstMessage * message, gpointer user_data)
|
|||
}
|
||||
|
||||
static void
|
||||
setup_pipeline (PvV4l2Source *source)
|
||||
setup_pipeline (PvGstSource *source)
|
||||
{
|
||||
PvV4l2SourcePrivate *priv = source->priv;
|
||||
PvGstSourcePrivate *priv = source->priv;
|
||||
GstBus *bus;
|
||||
GstElement *elem;
|
||||
|
||||
priv->pipeline = gst_parse_launch ("v4l2src name=src ! "
|
||||
"capsfilter name=filter ! "
|
||||
"pvfdpay ! "
|
||||
"multisocketsink "
|
||||
"buffers-max=2 "
|
||||
"buffers-soft-max=1 "
|
||||
"recover-policy=latest "
|
||||
"sync-method=latest "
|
||||
"name=sink "
|
||||
"sync=true "
|
||||
"enable-last-sample=false",
|
||||
priv->pipeline = gst_pipeline_new (NULL);
|
||||
|
||||
gst_bin_add (GST_BIN (priv->pipeline), priv->element);
|
||||
|
||||
priv->filter = gst_element_factory_make ("capsfilter", NULL);
|
||||
gst_bin_add (GST_BIN (priv->pipeline), priv->filter);
|
||||
gst_element_link (priv->element, priv->filter);
|
||||
|
||||
elem = gst_element_factory_make ("pvfdpay", NULL);
|
||||
gst_bin_add (GST_BIN (priv->pipeline), elem);
|
||||
gst_element_link (priv->filter, elem);
|
||||
|
||||
priv->sink = gst_element_factory_make ("multisocketsink", NULL);
|
||||
g_object_set (priv->sink, "buffers-max", 2,
|
||||
"buffers-soft-max", 1,
|
||||
"recover-policy", 1, /* latest */
|
||||
"sync-method", 0, /* latest */
|
||||
"sync", TRUE,
|
||||
"enable-last-sample", FALSE,
|
||||
NULL);
|
||||
priv->filter = gst_bin_get_by_name (GST_BIN (priv->pipeline), "filter");
|
||||
priv->sink = gst_bin_get_by_name (GST_BIN (priv->pipeline), "sink");
|
||||
priv->src = gst_bin_get_by_name (GST_BIN (priv->pipeline), "src");
|
||||
gst_bin_add (GST_BIN (priv->pipeline), priv->sink);
|
||||
gst_element_link (elem, priv->sink);
|
||||
|
||||
bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
|
||||
gst_bus_add_watch (bus, bus_handler, source);
|
||||
|
@ -93,10 +106,22 @@ setup_pipeline (PvV4l2Source *source)
|
|||
gst_element_set_state (priv->pipeline, GST_STATE_READY);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_pipeline (PvGstSource *source)
|
||||
{
|
||||
PvGstSourcePrivate *priv = source->priv;
|
||||
|
||||
if (priv->pipeline) {
|
||||
gst_element_set_state (priv->pipeline, GST_STATE_NULL);
|
||||
gst_object_unref (priv->pipeline);
|
||||
priv->pipeline = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
collect_caps (PvSource * source, GstCaps *filter)
|
||||
{
|
||||
PvV4l2SourcePrivate *priv = PV_V4L2_SOURCE (source)->priv;
|
||||
PvGstSourcePrivate *priv = PV_GST_SOURCE (source)->priv;
|
||||
GstCaps *res;
|
||||
GstQuery *query;
|
||||
|
||||
|
@ -110,9 +135,9 @@ collect_caps (PvSource * source, GstCaps *filter)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
v4l2_set_state (PvSource *source, PvSourceState state)
|
||||
set_state (PvSource *source, PvSourceState state)
|
||||
{
|
||||
PvV4l2SourcePrivate *priv = PV_V4L2_SOURCE (source)->priv;
|
||||
PvGstSourcePrivate *priv = PV_GST_SOURCE (source)->priv;
|
||||
|
||||
switch (state) {
|
||||
case PV_SOURCE_STATE_SUSPENDED:
|
||||
|
@ -139,7 +164,7 @@ v4l2_set_state (PvSource *source, PvSourceState state)
|
|||
}
|
||||
|
||||
static GBytes *
|
||||
v4l2_get_formats (PvSource *source, GBytes *filter)
|
||||
get_formats (PvSource *source, GBytes *filter)
|
||||
{
|
||||
GstCaps *caps, *cfilter;
|
||||
gchar *str;
|
||||
|
@ -162,8 +187,8 @@ on_socket_notify (GObject *gobject,
|
|||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvV4l2Source *source = user_data;
|
||||
PvV4l2SourcePrivate *priv = source->priv;
|
||||
PvGstSource *source = user_data;
|
||||
PvGstSourcePrivate *priv = source->priv;
|
||||
GSocket *socket;
|
||||
guint num_handles;
|
||||
GstCaps *caps;
|
||||
|
@ -219,7 +244,7 @@ on_socket_notify (GObject *gobject,
|
|||
}
|
||||
|
||||
static PvSourceOutput *
|
||||
v4l2_create_source_output (PvSource *source,
|
||||
create_source_output (PvSource *source,
|
||||
const gchar *client_path,
|
||||
GBytes *format_filter,
|
||||
const gchar *prefix,
|
||||
|
@ -241,7 +266,7 @@ v4l2_create_source_output (PvSource *source,
|
|||
str = gst_caps_to_string (filtered);
|
||||
format_filter = g_bytes_new_take (str, strlen (str) + 1);
|
||||
|
||||
output = PV_SOURCE_CLASS (pv_v4l2_source_parent_class)
|
||||
output = PV_SOURCE_CLASS (pv_gst_source_parent_class)
|
||||
->create_source_output (source,
|
||||
client_path,
|
||||
format_filter,
|
||||
|
@ -274,43 +299,109 @@ no_format:
|
|||
}
|
||||
|
||||
static gboolean
|
||||
v4l2_release_source_output (PvSource *source, PvSourceOutput *output)
|
||||
release_source_output (PvSource *source, PvSourceOutput *output)
|
||||
{
|
||||
return PV_SOURCE_CLASS (pv_v4l2_source_parent_class)->release_source_output (source, output);
|
||||
return PV_SOURCE_CLASS (pv_gst_source_parent_class)->release_source_output (source, output);
|
||||
}
|
||||
|
||||
static void
|
||||
v4l2_source_finalize (GObject * object)
|
||||
get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
G_OBJECT_CLASS (pv_v4l2_source_parent_class)->finalize (object);
|
||||
PvGstSource *source = PV_GST_SOURCE (object);
|
||||
PvGstSourcePrivate *priv = source->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ELEMENT:
|
||||
g_value_set_object (value, priv->element);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pv_v4l2_source_class_init (PvV4l2SourceClass * klass)
|
||||
set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PvGstSource *source = PV_GST_SOURCE (object);
|
||||
PvGstSourcePrivate *priv = source->priv;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ELEMENT:
|
||||
priv->element = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
source_constructed (GObject * object)
|
||||
{
|
||||
PvGstSource *source = PV_GST_SOURCE (object);
|
||||
|
||||
setup_pipeline (source);
|
||||
|
||||
G_OBJECT_CLASS (pv_gst_source_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
source_finalize (GObject * object)
|
||||
{
|
||||
PvGstSource *source = PV_GST_SOURCE (object);
|
||||
|
||||
destroy_pipeline (source);
|
||||
|
||||
G_OBJECT_CLASS (pv_gst_source_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pv_gst_source_class_init (PvGstSourceClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
PvSourceClass *source_class = PV_SOURCE_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (PvV4l2SourcePrivate));
|
||||
g_type_class_add_private (klass, sizeof (PvGstSourcePrivate));
|
||||
|
||||
gobject_class->finalize = v4l2_source_finalize;
|
||||
gobject_class->constructed = source_constructed;
|
||||
gobject_class->finalize = source_finalize;
|
||||
gobject_class->get_property = get_property;
|
||||
gobject_class->set_property = set_property;
|
||||
|
||||
source_class->get_formats = v4l2_get_formats;
|
||||
source_class->set_state = v4l2_set_state;
|
||||
source_class->create_source_output = v4l2_create_source_output;
|
||||
source_class->release_source_output = v4l2_release_source_output;
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ELEMENT,
|
||||
g_param_spec_object ("element",
|
||||
"Element",
|
||||
"The element",
|
||||
GST_TYPE_ELEMENT,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
|
||||
source_class->get_formats = get_formats;
|
||||
source_class->set_state = set_state;
|
||||
source_class->create_source_output = create_source_output;
|
||||
source_class->release_source_output = release_source_output;
|
||||
}
|
||||
|
||||
static void
|
||||
pv_v4l2_source_init (PvV4l2Source * source)
|
||||
pv_gst_source_init (PvGstSource * source)
|
||||
{
|
||||
source->priv = PV_V4L2_SOURCE_GET_PRIVATE (source);
|
||||
|
||||
setup_pipeline (source);
|
||||
source->priv = PV_GST_SOURCE_GET_PRIVATE (source);
|
||||
}
|
||||
|
||||
PvSource *
|
||||
pv_v4l2_source_new (PvDaemon *daemon)
|
||||
pv_gst_source_new (PvDaemon *daemon, const gchar *name, GstElement *element)
|
||||
{
|
||||
return g_object_new (PV_TYPE_V4L2_SOURCE, "daemon", daemon, "name", "v4l2", NULL);
|
||||
return g_object_new (PV_TYPE_GST_SOURCE, "daemon", daemon, "name", name, "element", element, NULL);
|
||||
}
|
61
src/modules/gst/pv-gst-source.h
Normal file
61
src/modules/gst/pv-gst-source.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* Pulsevideo
|
||||
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __PV_GST_SOURCE_H__
|
||||
#define __PV_GST_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <client/pulsevideo.h>
|
||||
#include <server/pv-daemon.h>
|
||||
#include <server/pv-source.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_GST_SOURCE (pv_gst_source_get_type ())
|
||||
#define PV_IS_GST_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_GST_SOURCE))
|
||||
#define PV_IS_GST_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_GST_SOURCE))
|
||||
#define PV_GST_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_GST_SOURCE, PvGstSourceClass))
|
||||
#define PV_GST_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_GST_SOURCE, PvGstSource))
|
||||
#define PV_GST_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_GST_SOURCE, PvGstSourceClass))
|
||||
#define PV_GST_SOURCE_CAST(obj) ((PvGstSource*)(obj))
|
||||
#define PV_GST_SOURCE_CLASS_CAST(klass) ((PvGstSourceClass*)(klass))
|
||||
|
||||
typedef struct _PvGstSource PvGstSource;
|
||||
typedef struct _PvGstSourceClass PvGstSourceClass;
|
||||
typedef struct _PvGstSourcePrivate PvGstSourcePrivate;
|
||||
|
||||
struct _PvGstSource {
|
||||
PvSource object;
|
||||
|
||||
PvGstSourcePrivate *priv;
|
||||
};
|
||||
|
||||
struct _PvGstSourceClass {
|
||||
PvSourceClass parent_class;
|
||||
};
|
||||
|
||||
GType pv_gst_source_get_type (void);
|
||||
|
||||
PvSource * pv_gst_source_new (PvDaemon *daemon, const gchar *name, GstElement *element);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_GST_SOURCE_H__ */
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/* Pulsevideo
|
||||
* Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __PV_V4L2_SOURCE_H__
|
||||
#define __PV_V4L2_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include <client/pulsevideo.h>
|
||||
#include <server/pv-daemon.h>
|
||||
#include <server/pv-source.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PV_TYPE_V4L2_SOURCE (pv_v4l2_source_get_type ())
|
||||
#define PV_IS_V4L2_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PV_TYPE_V4L2_SOURCE))
|
||||
#define PV_IS_V4L2_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PV_TYPE_V4L2_SOURCE))
|
||||
#define PV_V4L2_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PV_TYPE_V4L2_SOURCE, PvV4l2SourceClass))
|
||||
#define PV_V4L2_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PV_TYPE_V4L2_SOURCE, PvV4l2Source))
|
||||
#define PV_V4L2_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PV_TYPE_V4L2_SOURCE, PvV4l2SourceClass))
|
||||
#define PV_V4L2_SOURCE_CAST(obj) ((PvV4l2Source*)(obj))
|
||||
#define PV_V4L2_SOURCE_CLASS_CAST(klass) ((PvV4l2SourceClass*)(klass))
|
||||
|
||||
typedef struct _PvV4l2Source PvV4l2Source;
|
||||
typedef struct _PvV4l2SourceClass PvV4l2SourceClass;
|
||||
typedef struct _PvV4l2SourcePrivate PvV4l2SourcePrivate;
|
||||
|
||||
struct _PvV4l2Source {
|
||||
PvSource object;
|
||||
|
||||
PvV4l2SourcePrivate *priv;
|
||||
};
|
||||
|
||||
struct _PvV4l2SourceClass {
|
||||
PvSourceClass parent_class;
|
||||
};
|
||||
|
||||
GType pv_v4l2_source_get_type (void);
|
||||
|
||||
PvSource * pv_v4l2_source_new (PvDaemon *daemon);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PV_V4L2_SOURCE_H__ */
|
||||
|
|
@ -169,8 +169,6 @@ on_socket_notify (GObject *gobject,
|
|||
|
||||
g_object_get (gobject, "socket", &socket, NULL);
|
||||
|
||||
g_print ("source socket %p\n", socket);
|
||||
|
||||
if (socket == NULL) {
|
||||
GSocket *prev_socket = g_object_get_data (gobject, "last-socket");
|
||||
if (prev_socket) {
|
||||
|
@ -182,7 +180,6 @@ on_socket_notify (GObject *gobject,
|
|||
g_object_set_data (gobject, "last-socket", socket);
|
||||
|
||||
g_object_get (priv->sink, "num-handles", &num_handles, NULL);
|
||||
g_print ("num handles %d\n", num_handles);
|
||||
if (num_handles == 0) {
|
||||
gst_element_set_state (priv->pipeline, GST_STATE_READY);
|
||||
} else if (socket) {
|
||||
|
@ -190,7 +187,6 @@ on_socket_notify (GObject *gobject,
|
|||
|
||||
/* suggest what we provide */
|
||||
g_object_get (priv->input, "format", &format, NULL);
|
||||
g_print ("final format %s\n", (gchar *) g_bytes_get_data (format, NULL));
|
||||
g_object_set (gobject, "format", format, NULL);
|
||||
g_bytes_unref (format);
|
||||
|
||||
|
@ -253,13 +249,11 @@ on_input_socket_notify (GObject *gobject,
|
|||
GstCaps *caps;
|
||||
|
||||
g_object_get (gobject, "socket", &socket, NULL);
|
||||
g_print ("input socket %p\n", socket);
|
||||
|
||||
if (socket) {
|
||||
/* requested format is final format */
|
||||
g_object_get (gobject, "requested-format", &requested_format, NULL);
|
||||
g_assert (requested_format != NULL);
|
||||
g_print ("final format %s\n", (gchar *) g_bytes_get_data (requested_format, NULL));
|
||||
g_object_set (gobject, "format", requested_format, NULL);
|
||||
|
||||
/* and set as caps on the filter */
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "client/pulsevideo.h"
|
||||
|
||||
#include "server/pv-daemon.h"
|
||||
#include "server/pv-client.h"
|
||||
|
||||
#include "dbus/org-pulsevideo.h"
|
||||
|
||||
#include "modules/v4l2/pv-v4l2-source.h"
|
||||
|
||||
#define PV_DAEMON_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), PV_TYPE_DAEMON, PvDaemonPrivate))
|
||||
|
||||
|
@ -36,7 +36,6 @@ struct _PvDaemonPrivate
|
|||
guint id;
|
||||
GDBusConnection *connection;
|
||||
GDBusObjectManagerServer *server_manager;
|
||||
PvSubscribe *subscribe;
|
||||
|
||||
GList *sources;
|
||||
|
||||
|
@ -50,23 +49,6 @@ typedef struct {
|
|||
GList *objects;
|
||||
} SenderData;
|
||||
|
||||
static void
|
||||
on_server_subscription_event (PvSubscribe *subscribe,
|
||||
PvSubscriptionEvent event,
|
||||
PvSubscriptionFlags flags,
|
||||
GDBusProxy *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *name, *object_path;
|
||||
|
||||
name = g_dbus_proxy_get_name (object);
|
||||
object_path = g_dbus_proxy_get_object_path (object);
|
||||
|
||||
switch (flags) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
client_name_appeared_handler (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
|
@ -176,8 +158,13 @@ bus_acquired_handler (GDBusConnection *connection,
|
|||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
GDBusObjectManagerServer *manager = priv->server_manager;
|
||||
|
||||
priv->connection = connection;
|
||||
|
||||
export_server_object (daemon, manager);
|
||||
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -185,18 +172,6 @@ name_acquired_handler (GDBusConnection *connection,
|
|||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
PvDaemon *daemon = user_data;
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
GDBusObjectManagerServer *manager = priv->server_manager;
|
||||
|
||||
export_server_object (daemon, manager);
|
||||
|
||||
g_object_set (priv->subscribe, "service", PV_DBUS_SERVICE,
|
||||
"subscription-mask", PV_SUBSCRIPTION_FLAGS_ALL,
|
||||
"connection", connection,
|
||||
NULL);
|
||||
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -208,10 +183,9 @@ name_lost_handler (GDBusConnection *connection,
|
|||
PvDaemonPrivate *priv = daemon->priv;
|
||||
GDBusObjectManagerServer *manager = priv->server_manager;
|
||||
|
||||
g_object_set (priv->subscribe, "connection", connection, NULL);
|
||||
|
||||
g_dbus_object_manager_server_unexport (manager, PV_DBUS_OBJECT_SERVER);
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
priv->connection = connection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -395,8 +369,8 @@ pv_daemon_finalize (GObject * object)
|
|||
PvDaemon *daemon = PV_DAEMON_CAST (object);
|
||||
PvDaemonPrivate *priv = daemon->priv;
|
||||
|
||||
g_clear_object (&priv->server_manager);
|
||||
pv_daemon_stop (daemon);
|
||||
g_clear_object (&priv->server_manager);
|
||||
|
||||
G_OBJECT_CLASS (pv_daemon_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -418,11 +392,5 @@ pv_daemon_init (PvDaemon * daemon)
|
|||
|
||||
priv->server_manager = g_dbus_object_manager_server_new (PV_DBUS_OBJECT_PREFIX);
|
||||
priv->senders = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
priv->subscribe = pv_subscribe_new ();
|
||||
g_signal_connect (priv->subscribe,
|
||||
"subscription-event",
|
||||
(GCallback) on_server_subscription_event,
|
||||
daemon);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue