diff options
author | Wim Taymans <wtaymans@redhat.com> | 2015-07-10 16:05:29 +0200 |
---|---|---|
committer | Wim Taymans <wtaymans@redhat.com> | 2015-07-10 16:05:29 +0200 |
commit | 2f026995caef72381d1526fa923477cf52ee83eb (patch) | |
tree | ac41047e16994cdfaec2b05356b26d22a2cff112 | |
parent | 88699b2fa0d9f23f13f51b2c461d099d239a0cf2 (diff) |
device-monitor: port to GstDeviceMonitorGstDeviceMonitor
Use GstDeviceMonitor to monitor the GStreamer devices.
-rw-r--r-- | libcheese/cheese-camera-device-monitor.c | 305 | ||||
-rw-r--r-- | libcheese/cheese-camera-device-monitor.h | 7 | ||||
-rw-r--r-- | libcheese/cheese-camera-device.c | 269 | ||||
-rw-r--r-- | libcheese/cheese-camera-device.h | 9 | ||||
-rw-r--r-- | libcheese/cheese-camera.c | 141 | ||||
-rw-r--r-- | libcheese/cheese-camera.h | 4 | ||||
-rw-r--r-- | src/cheese-preferences.vala | 16 | ||||
-rw-r--r-- | src/vapi/cheese-common.vapi | 17 | ||||
-rw-r--r-- | tests/cheese-test-monitor.c | 6 |
9 files changed, 206 insertions, 568 deletions
diff --git a/libcheese/cheese-camera-device-monitor.c b/libcheese/cheese-camera-device-monitor.c index 9ef64737..48520edb 100644 --- a/libcheese/cheese-camera-device-monitor.c +++ b/libcheese/cheese-camera-device-monitor.c @@ -26,46 +26,25 @@ #include <glib-object.h> #include <string.h> -#ifdef HAVE_UDEV - #define G_UDEV_API_IS_SUBJECT_TO_CHANGE 1 - #include <gudev/gudev.h> -#else - #include <fcntl.h> - #include <unistd.h> - #include <sys/ioctl.h> - #if USE_SYS_VIDEOIO_H > 0 - #include <sys/types.h> - #include <sys/videoio.h> - #elif defined (__sun) - #include <sys/types.h> - #include <sys/videodev2.h> - #endif /* USE_SYS_VIDEOIO_H */ -#endif - #include "cheese-camera-device-monitor.h" /** * SECTION:cheese-camera-device-monitor - * @short_description: Simple object to enumerate v4l devices + * @short_description: Simple object to enumerate video devices * @stability: Unstable * @include: cheese/cheese-camera-device-monitor.h * - * #CheeseCameraDeviceMonitor provides a basic interface for video4linux device + * #CheeseCameraDeviceMonitor provides a basic interface for video device * enumeration and hotplugging. * - * It uses either GUdev or some platform specific code to list video devices. - * It is also capable (right now in Linux only, with the udev backend) to + * It uses GstDeviceMonitor to list video devices. It is also capable to * monitor device plugging and emit a CheeseCameraDeviceMonitor::added or * CheeseCameraDeviceMonitor::removed signal when an event happens. */ struct _CheeseCameraDeviceMonitorPrivate { -#ifdef HAVE_UDEV - GUdevClient *client; -#else - guint filler; -#endif /* HAVE_UDEV */ + GstDeviceMonitor *monitor; }; G_DEFINE_TYPE_WITH_PRIVATE (CheeseCameraDeviceMonitor, cheese_camera_device_monitor, G_TYPE_OBJECT) @@ -92,165 +71,100 @@ cheese_camera_device_monitor_error_quark (void) return g_quark_from_static_string ("cheese-camera-error-quark"); } -#ifdef HAVE_UDEV - /* * cheese_camera_device_monitor_set_up_device: - * @udevice: the device information from udev + * @device: the device information from GStreamer * - * Creates a new #CheeseCameraDevice for the supplied @udevice. + * Creates a new #CheeseCameraDevice for the supplied @device. * - * Returns: a new #CheeseCameraDevice, or %NULL if @udevice was not a V4L - * capture device + * Returns: a new #CheeseCameraDevice, or %NULL if @device was not an + * acceptable capture device */ static CheeseCameraDevice* -cheese_camera_device_monitor_set_up_device (GUdevDevice *udevice) +cheese_camera_device_monitor_set_up_device (GstDevice *device) { - const char *device_file; - const char *product_name; - const char *vendor; - const char *product; - const char *bus; - GError *error = NULL; - gint vendor_id = 0; - gint product_id = 0; - gint v4l_version = 0; - CheeseCameraDevice *device; - - const gchar *devpath = g_udev_device_get_property (udevice, "DEVPATH"); - - GST_INFO ("Checking udev device '%s'", devpath); - - bus = g_udev_device_get_property (udevice, "ID_BUS"); - if (g_strcmp0 (bus, "usb") == 0) - { - vendor = g_udev_device_get_property (udevice, "ID_VENDOR_ID"); - if (vendor != NULL) - vendor_id = g_ascii_strtoll (vendor, NULL, 16); - product = g_udev_device_get_property (udevice, "ID_MODEL_ID"); - if (product != NULL) - product_id = g_ascii_strtoll (product, NULL, 16); - if (vendor_id == 0 || product_id == 0) - { - GST_WARNING ("Error getting vendor and product id"); - } - else - { - GST_INFO ("Found device %04x:%04x, getting capabilities...", vendor_id, product_id); - } - } - else - { - GST_INFO ("Not an usb device, skipping vendor and model id retrieval"); - } + CheeseCameraDevice *newdev; + GError *error = NULL; - device_file = g_udev_device_get_device_file (udevice); - if (device_file == NULL) - { - GST_WARNING ("Error getting V4L device"); - return NULL; - } + newdev = cheese_camera_device_new (device, &error); - /* vbi devices support capture capability too, but cannot be used, - * so detect them by device name */ - if (strstr (device_file, "vbi")) - { - GST_INFO ("Skipping vbi device: %s", device_file); - return NULL; - } - - v4l_version = g_udev_device_get_property_as_int (udevice, "ID_V4L_VERSION"); - if (v4l_version == 2 || v4l_version == 1) - { - const char *caps; - - caps = g_udev_device_get_property (udevice, "ID_V4L_CAPABILITIES"); - if (caps == NULL || strstr (caps, ":capture:") == NULL) - { - GST_WARNING ("Device %s seems to not have the capture capability, (radio tuner?)" - "Removing it from device list.", device_file); - return NULL; - } - product_name = g_udev_device_get_property (udevice, "ID_V4L_PRODUCT"); - } - else if (v4l_version == 0) - { - GST_ERROR ("Fix your udev installation to include v4l_id, ignoring %s", device_file); - return NULL; - } - else - { - g_assert_not_reached (); - } - - device = cheese_camera_device_new (devpath, - device_file, - product_name, - v4l_version, - &error); - - if (device == NULL) - GST_WARNING ("Device initialization for %s failed: %s ", - device_file, + if (newdev == NULL) + GST_WARNING ("Device initialization for %p failed: %s ", + device, (error != NULL) ? error->message : "Unknown reason"); - return device; + return newdev; } /* * cheese_camera_device_monitor_added: * @monitor: a #CheeseCameraDeviceMonitor - * @udevice: the device information, from udev, for the device that was added + * @device: the device information, from GStreamer, for the device that was added * * Emits the ::added signal. */ static void cheese_camera_device_monitor_added (CheeseCameraDeviceMonitor *monitor, - GUdevDevice *udevice) + GstDevice *device) { - CheeseCameraDevice *device = cheese_camera_device_monitor_set_up_device (udevice); + CheeseCameraDevice *newdev = cheese_camera_device_monitor_set_up_device (device); /* Ignore non-video devices, GNOME bug #677544. */ - if (device) - g_signal_emit (monitor, monitor_signals[ADDED], 0, device); + if (newdev) { + g_object_set_data (G_OBJECT (device), "cheese-camera-device", newdev); + g_signal_emit (monitor, monitor_signals[ADDED], 0, newdev); + } } /* * cheese_camera_device_monitor_removed: * @monitor: a #CheeseCameraDeviceMonitor - * @udevice: the device information, from udev, for the device that was removed + * @device: the device information, from GStreamer, for the device that was removed * * Emits the ::removed signal. */ static void cheese_camera_device_monitor_removed (CheeseCameraDeviceMonitor *monitor, - GUdevDevice *udevice) + GstDevice *device) { - g_signal_emit (monitor, monitor_signals[REMOVED], 0, - g_udev_device_get_property (udevice, "DEVPATH")); + CheeseCameraDevice *olddev; + + olddev = g_object_get_data (G_OBJECT (device), "cheese-camera-device"); + if (olddev) + g_signal_emit (monitor, monitor_signals[REMOVED], 0, olddev); } /* - * cheese_camera_device_monitor_uevent_cb: - * @client: a #GUdevClient - * @action: the string representing the action type of the uevent - * @udevice: the #GUdevDevice to which the uevent refers - * @monitor: a #CheeseCameraDeviceMonitor + * cheese_camera_device_monitor_bus_func: + * @bus: a #GstBus + * @message: the message posted on the bus * - * Check if the uevent corresponds to device addition or removal, and if so, + * Check if the message corresponds to device addition or removal, and if so, * pass it on to cheese_camera_device_monitor_added() or * cheese_camera_device_monitor_removed() for emitting the ::added and * ::removed signals. */ -static void -cheese_camera_device_monitor_uevent_cb (GUdevClient *client, - const gchar *action, - GUdevDevice *udevice, - CheeseCameraDeviceMonitor *monitor) +static gboolean +cheese_camera_device_monitor_bus_func (GstBus *bus, + GstMessage *message, + gpointer user_data) { - if (g_str_equal (action, "remove")) - cheese_camera_device_monitor_removed (monitor, udevice); - else if (g_str_equal (action, "add")) - cheese_camera_device_monitor_added (monitor, udevice); + CheeseCameraDeviceMonitor *monitor = user_data; + GstDevice *device; + + switch (GST_MESSAGE_TYPE (message)) + { + case GST_MESSAGE_DEVICE_ADDED: + gst_message_parse_device_added (message, &device); + cheese_camera_device_monitor_added (monitor, device); + break; + case GST_MESSAGE_DEVICE_REMOVED: + gst_message_parse_device_removed (message, &device); + cheese_camera_device_monitor_removed (monitor, device); + break; + default: + break; + } + return G_SOURCE_CONTINUE; } /* @@ -266,7 +180,7 @@ static void cheese_camera_device_monitor_add_devices (gpointer data, gpointer user_data) { cheese_camera_device_monitor_added ((CheeseCameraDeviceMonitor *) user_data, - (GUdevDevice *) data); + (GstDevice *) data); g_object_unref (data); } @@ -288,11 +202,11 @@ cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor) priv = cheese_camera_device_monitor_get_instance_private (monitor); - g_return_if_fail (priv->client != NULL); + g_return_if_fail (priv->monitor != NULL); - GST_INFO ("Probing devices with udev..."); + GST_INFO ("Probing devices with GStreamer monitor..."); - devices = g_udev_client_query_by_subsystem (priv->client, "video4linux"); + devices = gst_device_monitor_get_devices (priv->monitor); if (devices == NULL) GST_WARNING ("No device found"); @@ -301,88 +215,16 @@ cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor) g_list_free (devices); } -#else /* HAVE_UDEV */ -void -cheese_camera_device_monitor_coldplug (CheeseCameraDeviceMonitor *monitor) -{ - #if 0 - CheeseCameraDeviceMonitorPrivate *priv = monitor->priv; - struct v4l2_capability v2cap; - struct video_capability v1cap; - int fd, ok; - - if ((fd = open (device_path, O_RDONLY | O_NONBLOCK)) < 0) - { - g_warning ("Failed to open %s: %s", device_path, strerror (errno)); - return; - } - ok = ioctl (fd, VIDIOC_QUERYCAP, &v2cap); - if (ok < 0) - { - ok = ioctl (fd, VIDIOCGCAP, &v1cap); - if (ok < 0) - { - g_warning ("Error while probing v4l capabilities for %s: %s", - device_path, strerror (errno)); - close (fd); - return; - } - g_print ("Detected v4l device: %s\n", v1cap.name); - g_print ("Device type: %d\n", v1cap.type); - gstreamer_src = "v4lsrc"; - product_name = v1cap.name; - } - else - { - guint cap = v2cap.capabilities; - g_print ("Detected v4l2 device: %s\n", v2cap.card); - g_print ("Driver: %s, version: %d\n", v2cap.driver, v2cap.version); - - /* g_print ("Bus info: %s\n", v2cap.bus_info); */ /* Doesn't seem anything useful */ - g_print ("Capabilities: 0x%08X\n", v2cap.capabilities); - if (!(cap & V4L2_CAP_VIDEO_CAPTURE)) - { - g_print ("Device %s seems to not have the capture capability, (radio tuner?)\n" - "Removing it from device list.\n", device_path); - close (fd); - return; - } - gstreamer_src = "v4l2src"; - product_name = (char *) v2cap.card; - } - close (fd); - - GList *devices, *l; - - g_print ("Probing devices with udev...\n"); - - if (priv->client == NULL) - return; - - devices = g_udev_client_query_by_subsystem (priv->client, "video4linux"); - - /* Initialize camera structures */ - for (l = devices; l != NULL; l = l->next) - { - cheese_camera_device_monitor_added (monitor, l->data); - g_object_unref (l->data); - } - g_list_free (devices); - #endif -} - -#endif /* HAVE_UDEV */ - static void cheese_camera_device_monitor_finalize (GObject *object) { -#ifdef HAVE_UDEV CheeseCameraDeviceMonitorPrivate *priv; priv = cheese_camera_device_monitor_get_instance_private (CHEESE_CAMERA_DEVICE_MONITOR (object)); - g_clear_object (&priv->client); -#endif /* HAVE_UDEV */ + gst_device_monitor_stop (priv->monitor); + g_clear_object (&priv->monitor); + G_OBJECT_CLASS (cheese_camera_device_monitor_parent_class)->finalize (object); } @@ -416,7 +258,7 @@ cheese_camera_device_monitor_class_init (CheeseCameraDeviceMonitorClass *klass) /** * CheeseCameraDeviceMonitor::removed: * @monitor: the #CheeseCameraDeviceMonitor that emitted the signal - * @uuid: UUID for the device on the system + * @device: the #CheeseCameraDevice that was removed * * The ::removed signal is emitted when a camera is unplugged, or disabled on * the system. @@ -426,20 +268,27 @@ cheese_camera_device_monitor_class_init (CheeseCameraDeviceMonitorClass *klass) G_STRUCT_OFFSET (CheeseCameraDeviceMonitorClass, removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); + G_TYPE_NONE, 1, CHEESE_TYPE_CAMERA_DEVICE); } static void cheese_camera_device_monitor_init (CheeseCameraDeviceMonitor *monitor) { -#ifdef HAVE_UDEV CheeseCameraDeviceMonitorPrivate *priv = cheese_camera_device_monitor_get_instance_private (monitor); - const gchar *const subsystems[] = {"video4linux", NULL}; + GstBus *bus; + GstCaps *caps; + + priv->monitor = gst_device_monitor_new (); + + bus = gst_device_monitor_get_bus (priv->monitor); + gst_bus_add_watch (bus, cheese_camera_device_monitor_bus_func, monitor); + gst_object_unref (bus); + + caps = gst_caps_new_empty_simple ("video/x-raw"); + gst_device_monitor_add_filter (priv->monitor, "Video/Source", caps); + gst_caps_unref (caps); - priv->client = g_udev_client_new (subsystems); - g_signal_connect (G_OBJECT (priv->client), "uevent", - G_CALLBACK (cheese_camera_device_monitor_uevent_cb), monitor); -#endif /* HAVE_UDEV */ + gst_device_monitor_start (priv->monitor); } /** diff --git a/libcheese/cheese-camera-device-monitor.h b/libcheese/cheese-camera-device-monitor.h index 1089000c..f11d0a4c 100644 --- a/libcheese/cheese-camera-device-monitor.h +++ b/libcheese/cheese-camera-device-monitor.h @@ -67,9 +67,10 @@ struct _CheeseCameraDeviceMonitorClass GObjectClass parent_class; /*< public >*/ - void (*added)(CheeseCameraDeviceMonitor *monitor, - CheeseCameraDevice *device); - void (*removed)(CheeseCameraDeviceMonitor *monitor, const gchar *uuid); + void (*added) (CheeseCameraDeviceMonitor *monitor, + CheeseCameraDevice *device); + void (*removed) (CheeseCameraDeviceMonitor *monitor, + CheeseCameraDevice *device); }; GType cheese_camera_device_monitor_get_type (void); diff --git a/libcheese/cheese-camera-device.c b/libcheese/cheese-camera-device.c index f4ff19d6..d96f78d5 100644 --- a/libcheese/cheese-camera-device.c +++ b/libcheese/cheese-camera-device.c @@ -86,9 +86,7 @@ enum { PROP_0, PROP_NAME, - PROP_DEVICE_NODE, - PROP_UUID, - PROP_V4LAPI_VERSION, + PROP_DEVICE, PROP_LAST }; @@ -96,15 +94,12 @@ static GParamSpec *properties[PROP_LAST]; typedef struct { - gchar *device_node; - gchar *uuid; - const gchar *src; - gchar *name; - guint v4lapi_version; - GstCaps *caps; - GList *formats; /* list members are CheeseVideoFormatFull structs. */ + GstDevice *device; + gchar *name; + GstCaps *caps; + GList *formats; /* list members are CheeseVideoFormatFull structs. */ - GError *construct_error; + GError *construct_error; } CheeseCameraDevicePrivate; G_DEFINE_TYPE_WITH_CODE (CheeseCameraDevice, cheese_camera_device, @@ -520,101 +515,34 @@ cheese_camera_device_update_format_table (CheeseCameraDevice *device) static void cheese_camera_device_get_caps (CheeseCameraDevice *device) { - CheeseCameraDevicePrivate *priv; - gchar *pipeline_desc; - GstElement *pipeline; - GstStateChangeReturn ret; - GstMessage *msg; - GstBus *bus; - GError *err = NULL; - - priv = cheese_camera_device_get_instance_private (device); - pipeline_desc = g_strdup_printf ("%s name=source device=%s ! fakesink", - priv->src, priv->device_node); - pipeline = gst_parse_launch (pipeline_desc, &err); - if ((pipeline != NULL) && (err == NULL)) - { - /* Start the pipeline and wait for max. 10 seconds for it to start up */ - gst_element_set_state (pipeline, GST_STATE_READY); - ret = gst_element_get_state (pipeline, NULL, NULL, 10 * GST_SECOND); - - /* Check if any error messages were posted on the bus */ - bus = gst_element_get_bus (pipeline); - msg = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR); - gst_object_unref (bus); - - if ((msg == NULL) && (ret == GST_STATE_CHANGE_SUCCESS)) - { - GstElement *src; - GstPad *pad; - GstCaps *caps; - - src = gst_bin_get_by_name (GST_BIN (pipeline), "source"); + CheeseCameraDevicePrivate *priv; + GstCaps *caps; - GST_LOG ("Device: %s (%s)\n", priv->name, priv->device_node); - pad = gst_element_get_static_pad (src, "src"); - caps = gst_pad_get_allowed_caps (pad); + priv = cheese_camera_device_get_instance_private (device); - gst_caps_unref (priv->caps); - priv->caps = cheese_camera_device_filter_caps (device, caps, supported_formats); + caps = gst_device_get_caps (priv->device); + if (caps == NULL) + caps = gst_caps_new_empty_simple ("video/x-raw"); - if (!gst_caps_is_empty (priv->caps)) - cheese_camera_device_update_format_table (device); - else - { - g_set_error_literal (&priv->construct_error, - CHEESE_CAMERA_DEVICE_ERROR, - CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS, - _("Device capabilities not supported")); - } + gst_caps_unref (priv->caps); + priv->caps = cheese_camera_device_filter_caps (device, caps, supported_formats); - gst_object_unref (pad); - gst_caps_unref (caps); - gst_object_unref (src); - } - else - { - if (msg) - { - gchar *dbg_info = NULL; - gst_message_parse_error (msg, &err, &dbg_info); - GST_WARNING ("Failed to start the capability probing pipeline"); - GST_WARNING ("Error from element %s: %s, %s", - GST_OBJECT_NAME (msg->src), - err->message, - (dbg_info) ? dbg_info : "no extra debug detail"); - g_error_free (err); - err = NULL; - - /* construct_error is meant to be displayed in the UI - * (although it currently isn't displayed in cheese), - * err->message from gstreamer is too technical for this - * purpose, the idea is warn the user about an error and point - * him to the logs for more info */ - g_set_error (&priv->construct_error, - CHEESE_CAMERA_DEVICE_ERROR, - CHEESE_CAMERA_DEVICE_ERROR_FAILED_INITIALIZATION, - _("Failed to initialize device %s for capability probing"), - priv->device_node); - } - } - gst_element_set_state (pipeline, GST_STATE_NULL); - gst_object_unref (pipeline); + if (!gst_caps_is_empty (priv->caps)) + cheese_camera_device_update_format_table (device); + else + { + g_set_error_literal (&priv->construct_error, + CHEESE_CAMERA_DEVICE_ERROR, + CHEESE_CAMERA_DEVICE_ERROR_UNSUPPORTED_CAPS, + _("Device capabilities not supported")); } - - if (err) - g_error_free (err); - - g_free (pipeline_desc); + gst_caps_unref (caps); } static void cheese_camera_device_constructed (GObject *object) { CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object); - CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device); - - priv->src = (priv->v4lapi_version == 2) ? "v4l2src" : "v4lsrc"; cheese_camera_device_get_caps (device); @@ -633,14 +561,8 @@ cheese_camera_device_get_property (GObject *object, guint prop_id, GValue *value case PROP_NAME: g_value_set_string (value, priv->name); break; - case PROP_DEVICE_NODE: - g_value_set_string (value, priv->device_node); - break; - case PROP_UUID: - g_value_set_string (value, priv->uuid); - break; - case PROP_V4LAPI_VERSION: - g_value_set_uint (value, priv->v4lapi_version); + case PROP_DEVICE: + g_value_set_object (value, priv->device); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -657,22 +579,15 @@ cheese_camera_device_set_property (GObject *object, guint prop_id, const GValue switch (prop_id) { case PROP_NAME: - if (priv->name) - g_free (priv->name); + g_free (priv->name); priv->name = g_value_dup_string (value); break; - case PROP_UUID: - if (priv->uuid) - g_free (priv->uuid); - priv->uuid = g_value_dup_string (value); - break; - case PROP_DEVICE_NODE: - if (priv->device_node) - g_free (priv->device_node); - priv->device_node = g_value_dup_string (value); - break; - case PROP_V4LAPI_VERSION: - priv->v4lapi_version = g_value_get_uint (value); + case PROP_DEVICE: + if (priv->device) + g_object_unref (priv->device); + priv->device = g_value_dup_object (value); + g_free (priv->name); + priv->name = gst_device_get_display_name (priv->device); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -686,8 +601,7 @@ cheese_camera_device_finalize (GObject *object) CheeseCameraDevice *device = CHEESE_CAMERA_DEVICE (object); CheeseCameraDevicePrivate *priv = cheese_camera_device_get_instance_private (device); - g_free (priv->device_node); - g_free (priv->uuid); + g_object_unref (priv->device); g_free (priv->name); gst_caps_unref (priv->caps); @@ -725,44 +639,17 @@ cheese_camera_device_class_init (CheeseCameraDeviceClass *klass) G_PARAM_STATIC_STRINGS); /** - * CheeseCameraDevice:device-node: + * CheeseCameraDevice:device: * - * Path to the device node of the video capture device. + * GStreamer device object of the video capture device. */ - properties[PROP_DEVICE_NODE] = g_param_spec_string ("device-node", - "Device node", - "Path to the device node of the video capture device", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - /** - * CheeseCameraDevice:uuid: - * - * UUID of the video capture device. - */ - properties[PROP_UUID] = g_param_spec_string ("uuid", - "Device UUID", - "UUID of the video capture device", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - /** - * CheeseCameraDevice:v4l-api-version: - * - * Version of the Video4Linux API that the device supports. Currently, either - * 1 or 2 are supported. - */ - properties[PROP_V4LAPI_VERSION] = g_param_spec_uint ("v4l-api-version", - "Video4Linux API version", - "Version of the Video4Linux API that the device supports", - 1, 2, 2, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); + properties[PROP_DEVICE] = g_param_spec_object ("device", + "Device", + "The GStreamer device object of the video capture device", + GST_TYPE_DEVICE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, PROP_LAST, properties); } @@ -815,32 +702,21 @@ cheese_camera_device_initable_init (GInitable *initable, /** * cheese_camera_device_new: - * @uuid: UUID of the device, as supplied by udev - * @device_node: (type filename): path to the device node of the video capture - * device - * @name: human-readable name of the device, as supplied by udev - * @v4l_api_version: version of the Video4Linux API that the device uses. Currently - * either 1 or 2 + * @device: The GStreamer the device, as supplied by GstDeviceMonitor * @error: a location to store errors * - * Tries to create a new #CheeseCameraDevice with the supplied parameters. If + * Tries to create a new #CheeseCameraDevice with the supplied device. If * construction fails, %NULL is returned, and @error is set. * * Returns: a new #CheeseCameraDevice, or %NULL */ CheeseCameraDevice * -cheese_camera_device_new (const gchar *uuid, - const gchar *device_node, - const gchar *name, - guint v4l_api_version, - GError **error) +cheese_camera_device_new (GstDevice *device, + GError **error) { return CHEESE_CAMERA_DEVICE (g_initable_new (CHEESE_TYPE_CAMERA_DEVICE, NULL, error, - "uuid", uuid, - "device-node", device_node, - "name", name, - "v4l-api-version", v4l_api_version, + "device", device, NULL)); } @@ -887,36 +763,14 @@ cheese_camera_device_get_name (CheeseCameraDevice *device) } /** - * cheese_camera_device_get_uuid: - * @device: a #CheeseCameraDevice - * - * Get the UUID of the @device, as reported by udev. - * - * Returns: (transfer none): the UUID of the video capture device - */ -const gchar * -cheese_camera_device_get_uuid (CheeseCameraDevice *device) -{ - CheeseCameraDevicePrivate *priv; - - g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL); - - priv = cheese_camera_device_get_instance_private (device); - - return priv->uuid; -} - -/** * cheese_camera_device_get_src: * @device: a #CheeseCameraDevice * - * Get the name of the source GStreamer element for the @device. Currently, - * this will be either v4lsrc or v4l2src, depending on the version of the - * Video4Linux API that the device supports. + * Get the source GStreamer element for the @device. * - * Returns: (transfer none): the name of the source GStreamer element + * Returns: (transfer full): the source GStreamer element */ -const gchar * +GstElement * cheese_camera_device_get_src (CheeseCameraDevice *device) { CheeseCameraDevicePrivate *priv; @@ -925,28 +779,7 @@ cheese_camera_device_get_src (CheeseCameraDevice *device) priv = cheese_camera_device_get_instance_private (device); - return priv->src; -} - -/** - * cheese_camera_device_get_device_node: - * @device: a #CheeseCameraDevice - * - * Get the path to the device node associated with the @device. - * - * Returns: (transfer none): the path to the device node of the video capture - * device - */ -const gchar * -cheese_camera_device_get_device_node (CheeseCameraDevice *device) -{ - CheeseCameraDevicePrivate *priv; - - g_return_val_if_fail (CHEESE_IS_CAMERA_DEVICE (device), NULL); - - priv = cheese_camera_device_get_instance_private (device); - - return priv->device_node; + return gst_device_create_element (priv->device, NULL); } /** diff --git a/libcheese/cheese-camera-device.h b/libcheese/cheese-camera-device.h index 45904611..4f5d819f 100644 --- a/libcheese/cheese-camera-device.h +++ b/libcheese/cheese-camera-device.h @@ -64,10 +64,7 @@ GType cheese_video_format_get_type (void); #define CHEESE_TYPE_CAMERA_DEVICE (cheese_camera_device_get_type ()) G_DECLARE_FINAL_TYPE (CheeseCameraDevice, cheese_camera_device, CHEESE, CAMERA_DEVICE, GObject) -CheeseCameraDevice *cheese_camera_device_new (const gchar *uuid, - const gchar *device_node, - const gchar *name, - guint v4l_api_version, +CheeseCameraDevice *cheese_camera_device_new (GstDevice *device, GError **error); GstCaps *cheese_camera_device_get_caps_for_format (CheeseCameraDevice *device, @@ -76,9 +73,7 @@ CheeseVideoFormat *cheese_camera_device_get_best_format (CheeseCameraDevice *dev GList * cheese_camera_device_get_format_list (CheeseCameraDevice *device); const gchar *cheese_camera_device_get_name (CheeseCameraDevice *device); -const gchar *cheese_camera_device_get_src (CheeseCameraDevice *device); -const gchar *cheese_camera_device_get_uuid (CheeseCameraDevice *device); -const gchar *cheese_camera_device_get_device_node (CheeseCameraDevice *device); +GstElement * cheese_camera_device_get_src (CheeseCameraDevice *device); G_END_DECLS diff --git a/libcheese/cheese-camera.c b/libcheese/cheese-camera.c index f15f2163..095636b2 100644 --- a/libcheese/cheese-camera.c +++ b/libcheese/cheese-camera.c @@ -84,7 +84,7 @@ struct _CheeseCameraPrivate gchar *photo_filename; guint num_camera_devices; - gchar *device_node; + CheeseCameraDevice *device; /* an array of CheeseCameraDevices */ GPtrArray *camera_devices; @@ -106,7 +106,7 @@ enum { PROP_0, PROP_VIDEO_TEXTURE, - PROP_DEVICE_NODE, + PROP_DEVICE, PROP_FORMAT, PROP_NUM_CAMERA_DEVICES, PROP_LAST @@ -312,34 +312,23 @@ cheese_camera_add_device (CheeseCameraDeviceMonitor *monitor, /* * cheese_camera_remove_device: * @monitor: a #CheeseCameraDeviceMonitor - * @uuid: UUId of a #CheeseCameraDevice + * @device: a #CheeseCameraDevice * @camera: a #CheeseCamera * * Handle the CheeseCameraDeviceMonitor::removed signal and remove the - * #CheeseCameraDevice associated with the UUID from the list of current - * devices. + * #CheeseCameraDevice from the list of current devices. */ static void cheese_camera_remove_device (CheeseCameraDeviceMonitor *monitor, - const gchar *uuid, + CheeseCameraDevice *device, CheeseCamera *camera) { - guint i; - - CheeseCameraPrivate *priv = cheese_camera_get_instance_private (camera); + CheeseCameraPrivate *priv = cheese_camera_get_instance_private (camera); - for (i = 0; i < priv->num_camera_devices; i++) + if (g_ptr_array_remove (priv->camera_devices, (gpointer) device)) { - CheeseCameraDevice *device = (CheeseCameraDevice *) g_ptr_array_index (priv->camera_devices, i); - const gchar *device_uuid = cheese_camera_device_get_uuid (device); - - if (strcmp (device_uuid, uuid) == 0) - { - g_ptr_array_remove (priv->camera_devices, (gpointer) device); - priv->num_camera_devices--; - g_object_notify_by_pspec (G_OBJECT (camera), properties[PROP_NUM_CAMERA_DEVICES]); - break; - } + priv->num_camera_devices--; + g_object_notify_by_pspec (G_OBJECT (camera), properties[PROP_NUM_CAMERA_DEVICES]); } } @@ -381,45 +370,48 @@ cheese_camera_set_camera_source (CheeseCamera *camera) { CheeseCameraPrivate *priv = cheese_camera_get_instance_private (camera); - GError *err = NULL; - gchar *camera_input; - - guint i; + guint i; CheeseCameraDevice *selected_camera; + GstElement *src, *filter; + GstPad *srcpad; if (priv->video_source) gst_object_unref (priv->video_source); /* If we have a matching video device use that one, otherwise use the first */ priv->selected_device = 0; - selected_camera = g_ptr_array_index (priv->camera_devices, 0); + selected_camera = g_ptr_array_index (priv->camera_devices, 0); for (i = 1; i < priv->num_camera_devices; i++) { - CheeseCameraDevice *device = g_ptr_array_index (priv->camera_devices, i); - if (g_strcmp0 (cheese_camera_device_get_device_node (device), - priv->device_node) == 0) + CheeseCameraDevice *dev = g_ptr_array_index (priv->camera_devices, i); + if (dev == priv->device) { - selected_camera = device; + selected_camera = dev; priv->selected_device = i; break; } } - camera_input = g_strdup_printf ( - "%s name=video_source device=%s ! capsfilter name=video_source_filter", - cheese_camera_device_get_src (selected_camera), - cheese_camera_device_get_device_node (selected_camera)); - - priv->video_source = gst_parse_bin_from_description (camera_input, TRUE, &err); - g_free (camera_input); - + priv->video_source = gst_bin_new (NULL); if (priv->video_source == NULL) { - g_clear_error(&err); return FALSE; } + src = cheese_camera_device_get_src (selected_camera); + gst_bin_add (GST_BIN (priv->video_source), src); + + filter = gst_element_factory_make ("capsfilter", "video_source_filter"); + gst_bin_add (GST_BIN (priv->video_source), filter); + + gst_element_link (src, filter); + + srcpad = gst_element_get_static_pad (filter, "src"); + gst_element_add_pad (priv->video_source, + gst_ghost_pad_new ("src", srcpad)); + gst_object_unref (srcpad); + return TRUE; } @@ -1270,7 +1262,7 @@ cheese_camera_finalize (GObject *object) if (priv->photo_filename) g_free (priv->photo_filename); g_free (priv->current_effect_desc); - g_free (priv->device_node); + g_object_unref (priv->device); g_boxed_free (CHEESE_TYPE_VIDEO_FORMAT, priv->current_format); /* Free CheeseCameraDevice array */ @@ -1296,8 +1288,8 @@ cheese_camera_get_property (GObject *object, guint prop_id, GValue *value, case PROP_VIDEO_TEXTURE: g_value_set_pointer (value, priv->video_texture); break; - case PROP_DEVICE_NODE: - g_value_set_string (value, priv->device_node); + case PROP_DEVICE: + g_value_set_object (value, priv->device); break; case PROP_FORMAT: g_value_set_boxed (value, priv->current_format); @@ -1326,9 +1318,9 @@ cheese_camera_set_property (GObject *object, guint prop_id, const GValue *value, case PROP_VIDEO_TEXTURE: priv->video_texture = g_value_get_pointer (value); break; - case PROP_DEVICE_NODE: - g_free (priv->device_node); - priv->device_node = g_value_dup_string (value); + case PROP_DEVICE: + g_object_unref (priv->device); + priv->device = g_value_dup_object (value); break; case PROP_FORMAT: if (priv->current_format != NULL) @@ -1422,16 +1414,16 @@ cheese_camera_class_init (CheeseCameraClass *klass) G_PARAM_STATIC_STRINGS); /** - * CheeseCamera:device-node: + * CheeseCamera:device: * - * The path to the device node for the video capture device. + * The device object to capture from. */ - properties[PROP_DEVICE_NODE] = g_param_spec_string ("device-node", - "Device node", - "The path to the device node for the video capture device", - "", - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS); + properties[PROP_DEVICE] = g_param_spec_object ("device", + "Device", + "The device object to capture from", + CHEESE_TYPE_CAMERA_DEVICE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); /** * CheeseCamera:format: @@ -1506,57 +1498,30 @@ cheese_camera_new (ClutterTexture *video_texture, const gchar *camera_device_nod } /** - * cheese_camera_set_device_by_device_node: + * cheese_camera_set_device: * @camera: a #CheeseCamera - * @file: (type filename): the device node path + * @device: the device object * - * Set the active video capture device of the @camera, matching by device node - * path. + * Set the active video capture device of the @camera. */ void -cheese_camera_set_device_by_device_node (CheeseCamera *camera, const gchar *file) +cheese_camera_set_device (CheeseCamera *camera, CheeseCameraDevice *device) { g_return_if_fail (CHEESE_IS_CAMERA (camera)); - g_object_set (camera, "device-node", file, NULL); -} - -/* - * cheese_camera_set_device_by_uuid: - * @camera: a #CheeseCamera - * @uuid: UUID of a #CheeseCameraDevice - * - * Set the active video capture device of the @camera, matching by UUID. - */ -static void -cheese_camera_set_device_by_dev_uuid (CheeseCamera *camera, const gchar *uuid) -{ - CheeseCameraPrivate *priv = cheese_camera_get_instance_private (camera); - guint i; - - for (i = 0; i < priv->num_camera_devices; i++) - { - CheeseCameraDevice *device = g_ptr_array_index (priv->camera_devices, i); - if (strcmp (cheese_camera_device_get_uuid (device), uuid) == 0) - { - g_object_set (camera, - "device-node", cheese_camera_device_get_uuid (device), - NULL); - break; - } - } + g_object_set (camera, "device", device, NULL); } /** * cheese_camera_setup: * @camera: a #CheeseCamera - * @uuid: (allow-none): UUID of the video capture device, or %NULL + * @device: (allow-none): the video capture device, or %NULL * @error: return location for a #GError, or %NULL * * Setup a video capture device. */ void -cheese_camera_setup (CheeseCamera *camera, const gchar *uuid, GError **error) +cheese_camera_setup (CheeseCamera *camera, CheeseCameraDevice *device, GError **error) { CheeseCameraPrivate *priv; GError *tmp_error = NULL; @@ -1575,9 +1540,9 @@ cheese_camera_setup (CheeseCamera *camera, const gchar *uuid, GError **error) return; } - if (uuid != NULL) + if (device != NULL) { - cheese_camera_set_device_by_dev_uuid (camera, uuid); + cheese_camera_set_device (camera, device); } diff --git a/libcheese/cheese-camera.h b/libcheese/cheese-camera.h index bbad2bd1..cd69a9ec 100644 --- a/libcheese/cheese-camera.h +++ b/libcheese/cheese-camera.h @@ -101,7 +101,7 @@ CheeseCamera *cheese_camera_new (ClutterTexture *video_texture, gint y_resolution); const CheeseVideoFormat *cheese_camera_get_current_video_format (CheeseCamera *camera); -void cheese_camera_setup (CheeseCamera *camera, const gchar *uuid, GError **error); +void cheese_camera_setup (CheeseCamera *camera, CheeseCameraDevice *device, GError **error); void cheese_camera_play (CheeseCamera *camera); void cheese_camera_stop (CheeseCamera *camera); void cheese_camera_set_effect (CheeseCamera *camera, CheeseEffect *effect); @@ -114,7 +114,7 @@ gboolean cheese_camera_take_photo (CheeseCamera *camera, const gchar gboolean cheese_camera_take_photo_pixbuf (CheeseCamera *camera); CheeseCameraDevice *cheese_camera_get_selected_device (CheeseCamera *camera); GPtrArray * cheese_camera_get_camera_devices (CheeseCamera *camera); -void cheese_camera_set_device_by_device_node (CheeseCamera *camera, const gchar *file); +void cheese_camera_set_device (CheeseCamera *camera, CheeseCameraDevice *device); void cheese_camera_switch_camera_device (CheeseCamera *camera); GList * cheese_camera_get_video_formats (CheeseCamera *camera); void cheese_camera_set_video_format (CheeseCamera *camera, diff --git a/src/cheese-preferences.vala b/src/cheese-preferences.vala index 21b68f38..8a3eb7ea 100644 --- a/src/cheese-preferences.vala +++ b/src/cheese-preferences.vala @@ -108,7 +108,7 @@ public PreferencesDialog (Cheese.Camera camera) devices.foreach(add_camera_device); - settings.set_string ("camera", camera.get_selected_device ().get_device_node ()); + settings.set_string ("camera", camera.get_selected_device ().get_name ()); setup_resolutions_for_device (camera.get_selected_device ()); } @@ -196,10 +196,10 @@ public PreferencesDialog (Cheese.Camera camera) combo.get_active_iter (out iter); combo.model.get (iter, 1, out dev); - camera.set_device_by_device_node (dev.get_device_node ()); + camera.set_device (dev); camera.switch_camera_device (); setup_resolutions_for_device (camera.get_selected_device ()); - settings.set_string ("camera", dev.get_device_node ()); + settings.set_string ("camera", dev.get_name ()); } /** @@ -387,7 +387,7 @@ public PreferencesDialog (Cheese.Camera camera) camera_model.get (iter, 1, out new_device, -1); // Found the device that was removed. - if (strcmp (old_device.device_node, new_device.device_node) != 0) + if (old_device != new_device) { remove_camera_device (iter, new_device, active_device); device_removed = true; @@ -406,7 +406,7 @@ public PreferencesDialog (Cheese.Camera camera) } } - settings.set_string ("camera", camera.get_selected_device ().get_device_node ()); + settings.set_string ("camera", camera.get_selected_device ().get_name ()); setup_resolutions_for_device (camera.get_selected_device ()); } @@ -425,10 +425,10 @@ public PreferencesDialog (Cheese.Camera camera) camera_model.append (out iter); camera_model.set (iter, - 0, dev.get_name () + " (" + dev.get_device_node () + ")", + 0, dev.get_name (), 1, dev); - if (camera.get_selected_device ().get_device_node () == dev.get_device_node ()) + if (camera.get_selected_device () == dev) source_combo.set_active_iter (iter); if (camera_model.iter_n_children (null) > 1) @@ -448,7 +448,7 @@ public PreferencesDialog (Cheese.Camera camera) unowned GLib.PtrArray devices = camera.get_camera_devices (); // Check if the camera that we want to remove, is the active one - if (strcmp (device_node.device_node, active_device_node.device_node) == 0) + if (device_node == active_device_node) { if (devices.len > 0) set_new_available_camera_device (iter); diff --git a/src/vapi/cheese-common.vapi b/src/vapi/cheese-common.vapi index a926725b..702d7012 100644 --- a/src/vapi/cheese-common.vapi +++ b/src/vapi/cheese-common.vapi @@ -43,8 +43,7 @@ namespace Cheese public bool has_camera (); public void play (); public void set_balance_property (string property, double value); - public void set_device_by_device_node (string file); - public void set_device_by_uuid (string uuid); + public void set_device (Cheese.CameraDevice device); public void set_effect (Cheese.Effect effect); public void toggle_effects_pipeline (bool active); public void connect_effect_texture (Cheese.Effect effect, Clutter.Texture texture); @@ -77,17 +76,13 @@ namespace Cheese public CameraDevice (string uuid, string device_node, string name, int v4lapi_version) throws GLib.Error; public Cheese.VideoFormat get_best_format (); public Gst.Caps get_caps_for_format (Cheese.VideoFormat format); - public unowned string get_device_node (); public GLib.List<unowned Cheese.VideoFormat> get_format_list (); - public unowned string get_uuid (); public unowned string get_name (); - public unowned string get_src (); + public Gst.Element get_src (); [NoAccessorMethod] - public uint v4l_api_version {get; construct;} - public string device_node {get; construct;} + public Gst.Device device {get; construct;} [NoAccessorMethod] - public string uuid {owned get; construct;} - public string name {get; construct;} + public string name {get;} } [CCode (cheader_filename = "cheese-camera-device-monitor.h")] @@ -96,8 +91,8 @@ namespace Cheese [CCode (has_construct_function = false)] public CameraDeviceMonitor (); public void coldplug (); - public virtual signal void added (string uuid, string device_file, string product_name, uint api_version); - public virtual signal void removed (string id); + public virtual signal void added (Gst.Device device); + public virtual signal void removed (Gst.Device device); } diff --git a/tests/cheese-test-monitor.c b/tests/cheese-test-monitor.c index 1afb871a..e2b99170 100644 --- a/tests/cheese-test-monitor.c +++ b/tests/cheese-test-monitor.c @@ -10,16 +10,16 @@ added_cb (CheeseCameraDeviceMonitor *monitor, CheeseCameraDevice *device, gpointer user_data) { - g_message ("Added new device with ID '%s'", cheese_camera_device_get_uuid (device)); + g_message ("Added new device with name '%s'", cheese_camera_device_get_name (device)); g_object_unref (device); } static void removed_cb (CheeseCameraDeviceMonitor *monitor, - const gchar *uuid, + const gchar *name, gpointer user_data) { - g_message ("Removed device with ID '%s'", uuid); + g_message ("Removed device with name '%s'", name); } int |