static void
gst_device_finalize (GObject * object)
{
  GstDevice *device = GST_DEVICE (object);

  gst_caps_replace (&device->priv->caps, NULL);

  g_free (device->priv->display_name);
  g_free (device->priv->device_class);

  G_OBJECT_CLASS (gst_device_parent_class)->finalize (object);
}
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);
  }
}
GList *
gst_device_monitor_get_devices (GstDeviceMonitor * monitor)
{
    GList *devices = NULL, *hidden = NULL;
    guint i;
    guint cookie;

    g_return_val_if_fail (GST_IS_DEVICE_MONITOR (monitor), NULL);

    GST_OBJECT_LOCK (monitor);

    if (monitor->priv->filters->len == 0) {
        GST_OBJECT_UNLOCK (monitor);
        GST_WARNING_OBJECT (monitor, "No filters have been set");
        return FALSE;
    }

    if (monitor->priv->providers->len == 0) {
        GST_OBJECT_UNLOCK (monitor);
        GST_WARNING_OBJECT (monitor, "No providers match the current filters");
        return FALSE;
    }

again:

    g_list_free_full (devices, gst_object_unref);
    g_list_free_full (hidden, g_free);
    devices = NULL;
    hidden = NULL;

    cookie = monitor->priv->cookie;

    for (i = 0; i < monitor->priv->providers->len; i++) {
        GList *tmpdev;
        GstDeviceProvider *provider =
            gst_object_ref (g_ptr_array_index (monitor->priv->providers, i));
        GList *item;

        if (!is_provider_hidden (monitor, hidden, provider)) {
            GST_OBJECT_UNLOCK (monitor);

            tmpdev = gst_device_provider_get_devices (provider);

            GST_OBJECT_LOCK (monitor);
            update_hidden_providers_list (&hidden, provider);
        } else {
            tmpdev = NULL;
        }


        for (item = tmpdev; item; item = item->next) {
            GstDevice *dev = GST_DEVICE (item->data);
            GstCaps *caps = gst_device_get_caps (dev);
            guint j;

            for (j = 0; j < monitor->priv->filters->len; j++) {
                struct DeviceFilter *filter =
                    g_ptr_array_index (monitor->priv->filters, j);

                if (gst_caps_can_intersect (filter->caps, caps) &&
                        gst_device_has_classesv (dev, filter->classesv)) {
                    devices = g_list_prepend (devices, gst_object_ref (dev));
                    break;
                }
            }
            gst_caps_unref (caps);
        }

        g_list_free_full (tmpdev, gst_object_unref);
        gst_object_unref (provider);

        if (monitor->priv->cookie != cookie)
            goto again;
    }
    g_list_free_full (hidden, g_free);

    GST_OBJECT_UNLOCK (monitor);

    return g_list_reverse (devices);
}
static GstDevice *
gst_v4l2_device_provider_device_from_udev (GstV4l2DeviceProvider * provider,
    GUdevDevice * udev_device)
{
  GstV4l2Device *gstdev;
  const gchar *device_path = g_udev_device_get_device_file (udev_device);
  const gchar *device_name, *str;
  GstStructure *props;

  props = gst_structure_new ("v4l2deviceprovider", "udev-probed",
      G_TYPE_BOOLEAN, TRUE, NULL);

  str = g_udev_device_get_property (udev_device, "ID_PATH");
  if (!(str && *str)) {
    str = g_udev_device_get_sysfs_path (udev_device);
  }
  if (str && *str)
    gst_structure_set (props, "device.bus_path", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_sysfs_path (udev_device)) && *str)
    gst_structure_set (props, "sysfs.path", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_property (udev_device, "ID_ID")) && *str)
    gst_structure_set (props, "udev.id", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_property (udev_device, "ID_BUS")) && *str)
    gst_structure_set (props, "device.bus", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_property (udev_device, "SUBSYSTEM")) && *str)
    gst_structure_set (props, "device.subsystem", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_property (udev_device, "ID_VENDOR_ID")) && *str)
    gst_structure_set (props, "device.vendor.id", G_TYPE_STRING, str, NULL);

  str = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE");
  if (!(str && *str)) {
    str = g_udev_device_get_property (udev_device, "ID_VENDOR_ENC");
    if (!(str && *str)) {
      str = g_udev_device_get_property (udev_device, "ID_VENDOR");
    }
  }
  if (str && *str)
    gst_structure_set (props, "device.vendor.name", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_property (udev_device, "ID_MODEL_ID")) && *str)
    gst_structure_set (props, "device.product.id", G_TYPE_STRING, str, NULL);

  device_name = g_udev_device_get_property (udev_device, "ID_V4L_PRODUCT");
  if (!(device_name && *device_name)) {
    device_name =
        g_udev_device_get_property (udev_device, "ID_MODEL_FROM_DATABASE");
    if (!(device_name && *device_name)) {
      device_name = g_udev_device_get_property (udev_device, "ID_MODEL_ENC");
      if (!(device_name && *device_name)) {
        device_name = g_udev_device_get_property (udev_device, "ID_MODEL");
      }
    }
  }
  if (device_name && *device_name)
    gst_structure_set (props, "device.product.name", G_TYPE_STRING, device_name,
        NULL);

  if ((str = g_udev_device_get_property (udev_device, "ID_SERIAL")) && *str)
    gst_structure_set (props, "device.serial", G_TYPE_STRING, str, NULL);

  if ((str = g_udev_device_get_property (udev_device, "ID_V4L_CAPABILITIES"))
      && *str)
    gst_structure_set (props, "device.capabilities", G_TYPE_STRING, str, NULL);

  gstdev = gst_v4l2_device_provider_probe_device (provider, device_path,
      device_name, props);

  if (gstdev)
    gstdev->syspath = g_strdup (g_udev_device_get_sysfs_path (udev_device));

  return GST_DEVICE (gstdev);
}