static void bus_sync_message (GstBus * bus, GstMessage * message, GstDeviceMonitor * monitor) { GstMessageType type = GST_MESSAGE_TYPE (message); if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) { gboolean matches; GstDevice *device; GstDeviceProvider *provider; if (type == GST_MESSAGE_DEVICE_ADDED) gst_message_parse_device_added (message, &device); else gst_message_parse_device_removed (message, &device); GST_OBJECT_LOCK (monitor); provider = GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device))); if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) { matches = FALSE; } else if (monitor->priv->filters->len) { guint i; for (i = 0; i < monitor->priv->filters->len; i++) { struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i); GstCaps *caps; caps = gst_device_get_caps (device); matches = gst_caps_can_intersect (filter->caps, caps) && gst_device_has_classesv (device, filter->classesv); gst_caps_unref (caps); if (matches) break; } } else { matches = TRUE; } GST_OBJECT_UNLOCK (monitor); gst_object_unref (provider); gst_object_unref (device); if (matches) gst_bus_post (monitor->priv->bus, gst_message_ref (message)); } }
static void uevent_cb (GUdevClient * client, const gchar * action, GUdevDevice * device, GstV4l2DeviceProvider * self) { GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); /* Not V4L2, ignoring */ if (g_udev_device_get_property_as_int (device, "ID_V4L_VERSION") != 2) return; if (!strcmp (action, "add")) { GstDevice *gstdev = NULL; gstdev = gst_v4l2_device_provider_device_from_udev (self, device); if (gstdev) gst_device_provider_device_add (provider, gstdev); } else if (!strcmp (action, "remove")) { GstV4l2Device *gstdev = NULL; GList *item; GST_OBJECT_LOCK (self); for (item = provider->devices; item; item = item->next) { gstdev = item->data; if (!strcmp (gstdev->syspath, g_udev_device_get_sysfs_path (device))) { gst_object_ref (gstdev); break; } gstdev = NULL; } GST_OBJECT_UNLOCK (provider); if (gstdev) { gst_device_provider_device_remove (provider, GST_DEVICE (gstdev)); g_object_unref (gstdev); } } else { GST_WARNING ("Unhandled action %s", action); } }
static gpointer provider_thread (gpointer data) { GstV4l2DeviceProvider *provider = data; GMainContext *context = NULL; GMainLoop *loop = NULL; GUdevClient *client; GList *devices; static const gchar *subsystems[] = { "video4linux", NULL }; GST_OBJECT_LOCK (provider); if (provider->context) context = g_main_context_ref (provider->context); if (provider->loop) loop = g_main_loop_ref (provider->loop); if (context == NULL || loop == NULL) { provider->started = TRUE; g_cond_broadcast (&provider->started_cond); GST_OBJECT_UNLOCK (provider); return NULL; } GST_OBJECT_UNLOCK (provider); g_main_context_push_thread_default (context); client = g_udev_client_new (subsystems); g_signal_connect (client, "uevent", G_CALLBACK (uevent_cb), provider); devices = g_udev_client_query_by_subsystem (client, "video4linux"); while (devices) { GUdevDevice *udev_device = devices->data; GstDevice *gstdev; devices = g_list_remove (devices, udev_device); if (g_udev_device_get_property_as_int (udev_device, "ID_V4L_VERSION") == 2) { gstdev = gst_v4l2_device_provider_device_from_udev (provider, udev_device); if (gstdev) gst_device_provider_device_add (GST_DEVICE_PROVIDER (provider), gstdev); } g_object_unref (udev_device); } GST_OBJECT_LOCK (provider); provider->started = TRUE; g_cond_broadcast (&provider->started_cond); GST_OBJECT_UNLOCK (provider); g_main_loop_run (loop); g_main_loop_unref (loop); g_object_unref (client); g_main_context_unref (context); gst_object_unref (provider); return NULL; }