Blame sys/v4l2/gstv4l2deviceprovider.c

Packit 1f69a5
/* GStreamer
Packit 1f69a5
 * Copyright (C) 2012 Olivier Crete <olivier.crete@collabora.com>
Packit 1f69a5
 *
Packit 1f69a5
 * gstv4l2deviceprovider.c: V4l2 device probing and monitoring
Packit 1f69a5
 *
Packit 1f69a5
 * This library is free software; you can redistribute it and/or
Packit 1f69a5
 * modify it under the terms of the GNU Library General Public
Packit 1f69a5
 * License as published by the Free Software Foundation; either
Packit 1f69a5
 * version 2 of the License, or (at your option) any later version.
Packit 1f69a5
 *
Packit 1f69a5
 * This library is distributed in the hope that it will be useful,
Packit 1f69a5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1f69a5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1f69a5
 * Library General Public License for more details.
Packit 1f69a5
 *
Packit 1f69a5
 * You should have received a copy of the GNU Library General Public
Packit 1f69a5
 * License along with this library; if not, write to the
Packit 1f69a5
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 1f69a5
 * Boston, MA 02111-1307, USA.
Packit 1f69a5
 */
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_CONFIG_H
Packit 1f69a5
#include "config.h"
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
#include "gstv4l2deviceprovider.h"
Packit 1f69a5
Packit 1f69a5
#include <string.h>
Packit 1f69a5
#include <sys/stat.h>
Packit 1f69a5
Packit 1f69a5
#include <gst/gst.h>
Packit 1f69a5
Packit 1f69a5
#include "gstv4l2object.h"
Packit 1f69a5
#include "v4l2-utils.h"
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_GUDEV
Packit 1f69a5
#include <gudev/gudev.h>
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
static GstV4l2Device *gst_v4l2_device_new (const gchar * device_path,
Packit 1f69a5
    const gchar * device_name, GstCaps * caps, GstV4l2DeviceType type,
Packit 1f69a5
    GstStructure * props);
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
G_DEFINE_TYPE (GstV4l2DeviceProvider, gst_v4l2_device_provider,
Packit 1f69a5
    GST_TYPE_DEVICE_PROVIDER);
Packit 1f69a5
Packit 1f69a5
static void gst_v4l2_device_provider_finalize (GObject * object);
Packit 1f69a5
static GList *gst_v4l2_device_provider_probe (GstDeviceProvider * provider);
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_GUDEV
Packit 1f69a5
static gboolean gst_v4l2_device_provider_start (GstDeviceProvider * provider);
Packit 1f69a5
static void gst_v4l2_device_provider_stop (GstDeviceProvider * provider);
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_provider_class_init (GstV4l2DeviceProviderClass * klass)
Packit 1f69a5
{
Packit 1f69a5
  GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
Packit 1f69a5
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit 1f69a5
Packit 1f69a5
  dm_class->probe = gst_v4l2_device_provider_probe;
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_GUDEV
Packit 1f69a5
  dm_class->start = gst_v4l2_device_provider_start;
Packit 1f69a5
  dm_class->stop = gst_v4l2_device_provider_stop;
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
  gobject_class->finalize = gst_v4l2_device_provider_finalize;
Packit 1f69a5
Packit 1f69a5
  gst_device_provider_class_set_static_metadata (dm_class,
Packit 1f69a5
      "Video (video4linux2) Device Provider", "Source/Sink/Video",
Packit 1f69a5
      "List and monitor video4linux2 source and sink devices",
Packit 1f69a5
      "Olivier Crete <olivier.crete@collabora.com>");
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_provider_init (GstV4l2DeviceProvider * provider)
Packit 1f69a5
{
Packit 1f69a5
#ifdef HAVE_GUDEV
Packit 1f69a5
  g_cond_init (&provider->started_cond);
Packit 1f69a5
#endif
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_provider_finalize (GObject * object)
Packit 1f69a5
{
Packit 1f69a5
#ifdef HAVE_GUDEV
Packit 1f69a5
  GstV4l2DeviceProvider *provider = GST_V4L2_DEVICE_PROVIDER (object);
Packit 1f69a5
Packit 1f69a5
  g_cond_clear (&provider->started_cond);
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
  G_OBJECT_CLASS (gst_v4l2_device_provider_parent_class)->finalize (object);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstV4l2Device *
Packit 1f69a5
gst_v4l2_device_provider_probe_device (GstV4l2DeviceProvider * provider,
Packit 1f69a5
    const gchar * device_path, const gchar * device_name, GstStructure * props)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Object *v4l2obj = NULL;
Packit 1f69a5
  GstCaps *caps;
Packit 1f69a5
  GstV4l2Device *device = NULL;
Packit 1f69a5
  struct stat st;
Packit 1f69a5
  GstV4l2DeviceType type = GST_V4L2_DEVICE_TYPE_INVALID;
Packit 1f69a5
Packit 1f69a5
  g_return_val_if_fail (props != NULL, NULL);
Packit 1f69a5
Packit 1f69a5
  if (stat (device_path, &st) == -1)
Packit 1f69a5
    goto destroy;
Packit 1f69a5
Packit 1f69a5
  if (!S_ISCHR (st.st_mode))
Packit 1f69a5
    goto destroy;
Packit 1f69a5
Packit 1f69a5
  v4l2obj = gst_v4l2_object_new (NULL, GST_OBJECT (provider),
Packit 1f69a5
      V4L2_BUF_TYPE_VIDEO_CAPTURE, device_path, NULL, NULL, NULL);
Packit 1f69a5
Packit 1f69a5
  if (!gst_v4l2_open (v4l2obj))
Packit 1f69a5
    goto destroy;
Packit 1f69a5
Packit 1f69a5
  gst_structure_set (props, "device.api", G_TYPE_STRING, "v4l2", NULL);
Packit 1f69a5
  gst_structure_set (props, "device.path", G_TYPE_STRING, device_path, NULL);
Packit 1f69a5
Packit 1f69a5
  gst_structure_set (props, "v4l2.device.driver", G_TYPE_STRING,
Packit 1f69a5
      v4l2obj->vcap.driver, NULL);
Packit 1f69a5
  gst_structure_set (props, "v4l2.device.card", G_TYPE_STRING,
Packit 1f69a5
      v4l2obj->vcap.card, NULL);
Packit 1f69a5
  gst_structure_set (props, "v4l2.device.bus_info", G_TYPE_STRING,
Packit 1f69a5
      v4l2obj->vcap.bus_info, NULL);
Packit 1f69a5
  gst_structure_set (props, "v4l2.device.version", G_TYPE_UINT,
Packit 1f69a5
      v4l2obj->vcap.version, NULL);
Packit 1f69a5
  gst_structure_set (props, "v4l2.device.capabilities", G_TYPE_UINT,
Packit 1f69a5
      v4l2obj->vcap.capabilities, NULL);
Packit 1f69a5
  gst_structure_set (props, "v4l2.device.device_caps", G_TYPE_UINT,
Packit 1f69a5
      v4l2obj->vcap.device_caps, NULL);
Packit 1f69a5
Packit 1f69a5
  if (v4l2obj->device_caps &
Packit 1f69a5
      (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
Packit 1f69a5
    /* We ignore touch sensing devices; those are't really video */
Packit 1f69a5
    if (v4l2obj->device_caps & V4L2_CAP_TOUCH)
Packit 1f69a5
      goto close;
Packit 1f69a5
Packit 1f69a5
    type = GST_V4L2_DEVICE_TYPE_SOURCE;
Packit 1f69a5
    v4l2obj->skip_try_fmt_probes = TRUE;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  if (v4l2obj->device_caps &
Packit 1f69a5
      (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)) {
Packit 1f69a5
    /* We ignore M2M devices that are both capture and output for now
Packit 1f69a5
     * The provider is not for them */
Packit 1f69a5
    if (type != GST_V4L2_DEVICE_TYPE_INVALID)
Packit 1f69a5
      goto close;
Packit 1f69a5
Packit 1f69a5
    type = GST_V4L2_DEVICE_TYPE_SINK;
Packit 1f69a5
Packit 1f69a5
    /* We have opened as a capture as we didn't know, now that know,
Packit 1f69a5
     * let's fixed it */
Packit 1f69a5
    if (v4l2obj->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
Packit 1f69a5
      v4l2obj->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
Packit 1f69a5
    else
Packit 1f69a5
      v4l2obj->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  if (type == GST_V4L2_DEVICE_TYPE_INVALID)
Packit 1f69a5
    goto close;
Packit 1f69a5
Packit 1f69a5
  caps = gst_v4l2_object_get_caps (v4l2obj, NULL);
Packit 1f69a5
Packit 1f69a5
  if (caps == NULL)
Packit 1f69a5
    goto close;
Packit 1f69a5
  if (gst_caps_is_empty (caps)) {
Packit 1f69a5
    gst_caps_unref (caps);
Packit 1f69a5
    goto close;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  device = gst_v4l2_device_new (device_path,
Packit 1f69a5
      device_name ? device_name : (gchar *) v4l2obj->vcap.card, caps, type,
Packit 1f69a5
      props);
Packit 1f69a5
  gst_caps_unref (caps);
Packit 1f69a5
Packit 1f69a5
close:
Packit 1f69a5
Packit 1f69a5
  gst_v4l2_close (v4l2obj);
Packit 1f69a5
Packit 1f69a5
destroy:
Packit 1f69a5
Packit 1f69a5
  if (v4l2obj)
Packit 1f69a5
    gst_v4l2_object_destroy (v4l2obj);
Packit 1f69a5
Packit 1f69a5
  if (props)
Packit 1f69a5
    gst_structure_free (props);
Packit 1f69a5
Packit 1f69a5
  return device;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
static GList *
Packit 1f69a5
gst_v4l2_device_provider_probe (GstDeviceProvider * provider)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider);
Packit 1f69a5
  GstV4l2Iterator *it;
Packit 1f69a5
  GList *devices = NULL;
Packit 1f69a5
Packit 1f69a5
  it = gst_v4l2_iterator_new ();
Packit 1f69a5
Packit 1f69a5
  while (gst_v4l2_iterator_next (it)) {
Packit 1f69a5
    GstStructure *props;
Packit 1f69a5
    GstV4l2Device *device;
Packit 1f69a5
Packit 1f69a5
    props = gst_structure_new ("v4l2-proplist", "device.path", G_TYPE_STRING,
Packit 1f69a5
        it->device_path, "udev-probed", G_TYPE_BOOLEAN, FALSE, NULL);
Packit 1f69a5
    device = gst_v4l2_device_provider_probe_device (self, it->device_path, NULL,
Packit 1f69a5
        props);
Packit 1f69a5
Packit 1f69a5
    if (device) {
Packit 1f69a5
      gst_object_ref_sink (device);
Packit 1f69a5
      devices = g_list_prepend (devices, device);
Packit 1f69a5
    }
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  gst_v4l2_iterator_free (it);
Packit 1f69a5
Packit 1f69a5
  return devices;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
#ifdef HAVE_GUDEV
Packit 1f69a5
Packit 1f69a5
static GstDevice *
Packit 1f69a5
gst_v4l2_device_provider_device_from_udev (GstV4l2DeviceProvider * provider,
Packit 1f69a5
    GUdevDevice * udev_device)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Device *gstdev;
Packit 1f69a5
  const gchar *device_path = g_udev_device_get_device_file (udev_device);
Packit 1f69a5
  const gchar *device_name, *str;
Packit 1f69a5
  GstStructure *props;
Packit 1f69a5
Packit 1f69a5
  props = gst_structure_new ("v4l2deviceprovider", "udev-probed",
Packit 1f69a5
      G_TYPE_BOOLEAN, TRUE, NULL);
Packit 1f69a5
Packit 1f69a5
  str = g_udev_device_get_property (udev_device, "ID_PATH");
Packit 1f69a5
  if (!(str && *str)) {
Packit 1f69a5
    str = g_udev_device_get_sysfs_path (udev_device);
Packit 1f69a5
  }
Packit 1f69a5
  if (str && *str)
Packit 1f69a5
    gst_structure_set (props, "device.bus_path", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_sysfs_path (udev_device)) && *str)
Packit 1f69a5
    gst_structure_set (props, "sysfs.path", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "ID_ID")) && *str)
Packit 1f69a5
    gst_structure_set (props, "udev.id", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "ID_BUS")) && *str)
Packit 1f69a5
    gst_structure_set (props, "device.bus", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "SUBSYSTEM")) && *str)
Packit 1f69a5
    gst_structure_set (props, "device.subsystem", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "ID_VENDOR_ID")) && *str)
Packit 1f69a5
    gst_structure_set (props, "device.vendor.id", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  str = g_udev_device_get_property (udev_device, "ID_VENDOR_FROM_DATABASE");
Packit 1f69a5
  if (!(str && *str)) {
Packit 1f69a5
    str = g_udev_device_get_property (udev_device, "ID_VENDOR_ENC");
Packit 1f69a5
    if (!(str && *str)) {
Packit 1f69a5
      str = g_udev_device_get_property (udev_device, "ID_VENDOR");
Packit 1f69a5
    }
Packit 1f69a5
  }
Packit 1f69a5
  if (str && *str)
Packit 1f69a5
    gst_structure_set (props, "device.vendor.name", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "ID_MODEL_ID")) && *str)
Packit 1f69a5
    gst_structure_set (props, "device.product.id", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  device_name = g_udev_device_get_property (udev_device, "ID_V4L_PRODUCT");
Packit 1f69a5
  if (!(device_name && *device_name)) {
Packit 1f69a5
    device_name =
Packit 1f69a5
        g_udev_device_get_property (udev_device, "ID_MODEL_FROM_DATABASE");
Packit 1f69a5
    if (!(device_name && *device_name)) {
Packit 1f69a5
      device_name = g_udev_device_get_property (udev_device, "ID_MODEL_ENC");
Packit 1f69a5
      if (!(device_name && *device_name)) {
Packit 1f69a5
        device_name = g_udev_device_get_property (udev_device, "ID_MODEL");
Packit 1f69a5
      }
Packit 1f69a5
    }
Packit 1f69a5
  }
Packit 1f69a5
  if (device_name && *device_name)
Packit 1f69a5
    gst_structure_set (props, "device.product.name", G_TYPE_STRING, device_name,
Packit 1f69a5
        NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "ID_SERIAL")) && *str)
Packit 1f69a5
    gst_structure_set (props, "device.serial", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  if ((str = g_udev_device_get_property (udev_device, "ID_V4L_CAPABILITIES"))
Packit 1f69a5
      && *str)
Packit 1f69a5
    gst_structure_set (props, "device.capabilities", G_TYPE_STRING, str, NULL);
Packit 1f69a5
Packit 1f69a5
  gstdev = gst_v4l2_device_provider_probe_device (provider, device_path,
Packit 1f69a5
      device_name, props);
Packit 1f69a5
Packit 1f69a5
  if (gstdev)
Packit 1f69a5
    gstdev->syspath = g_strdup (g_udev_device_get_sysfs_path (udev_device));
Packit 1f69a5
Packit 1f69a5
  return GST_DEVICE (gstdev);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
uevent_cb (GUdevClient * client, const gchar * action, GUdevDevice * device,
Packit 1f69a5
    GstV4l2DeviceProvider * self)
Packit 1f69a5
{
Packit 1f69a5
  GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self);
Packit 1f69a5
Packit 1f69a5
  /* Not V4L2, ignoring */
Packit 1f69a5
  if (g_udev_device_get_property_as_int (device, "ID_V4L_VERSION") != 2)
Packit 1f69a5
    return;
Packit 1f69a5
Packit 1f69a5
  if (!strcmp (action, "add")) {
Packit 1f69a5
    GstDevice *gstdev = NULL;
Packit 1f69a5
Packit 1f69a5
    gstdev = gst_v4l2_device_provider_device_from_udev (self, device);
Packit 1f69a5
Packit 1f69a5
    if (gstdev)
Packit 1f69a5
      gst_device_provider_device_add (provider, gstdev);
Packit 1f69a5
  } else if (!strcmp (action, "remove")) {
Packit 1f69a5
    GstV4l2Device *gstdev = NULL;
Packit 1f69a5
    GList *item;
Packit 1f69a5
Packit 1f69a5
    GST_OBJECT_LOCK (self);
Packit 1f69a5
    for (item = provider->devices; item; item = item->next) {
Packit 1f69a5
      gstdev = item->data;
Packit 1f69a5
Packit 1f69a5
      if (!strcmp (gstdev->syspath, g_udev_device_get_sysfs_path (device))) {
Packit 1f69a5
        gst_object_ref (gstdev);
Packit 1f69a5
        break;
Packit 1f69a5
      }
Packit 1f69a5
Packit 1f69a5
      gstdev = NULL;
Packit 1f69a5
    }
Packit 1f69a5
    GST_OBJECT_UNLOCK (provider);
Packit 1f69a5
Packit 1f69a5
    if (gstdev) {
Packit 1f69a5
      gst_device_provider_device_remove (provider, GST_DEVICE (gstdev));
Packit 1f69a5
      g_object_unref (gstdev);
Packit 1f69a5
    }
Packit 1f69a5
  } else {
Packit 1f69a5
    GST_WARNING ("Unhandled action %s", action);
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gpointer
Packit 1f69a5
provider_thread (gpointer data)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2DeviceProvider *provider = data;
Packit 1f69a5
  GMainContext *context = NULL;
Packit 1f69a5
  GMainLoop *loop = NULL;
Packit 1f69a5
  GUdevClient *client;
Packit 1f69a5
  GList *devices;
Packit 1f69a5
  static const gchar *subsystems[] = { "video4linux", NULL };
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (provider);
Packit 1f69a5
  if (provider->context)
Packit 1f69a5
    context = g_main_context_ref (provider->context);
Packit 1f69a5
  if (provider->loop)
Packit 1f69a5
    loop = g_main_loop_ref (provider->loop);
Packit 1f69a5
Packit 1f69a5
  if (context == NULL || loop == NULL) {
Packit 1f69a5
    provider->started = TRUE;
Packit 1f69a5
    g_cond_broadcast (&provider->started_cond);
Packit 1f69a5
    GST_OBJECT_UNLOCK (provider);
Packit 1f69a5
    return NULL;
Packit 1f69a5
  }
Packit 1f69a5
  GST_OBJECT_UNLOCK (provider);
Packit 1f69a5
Packit 1f69a5
  g_main_context_push_thread_default (context);
Packit 1f69a5
Packit 1f69a5
  client = g_udev_client_new (subsystems);
Packit 1f69a5
Packit 1f69a5
  g_signal_connect (client, "uevent", G_CALLBACK (uevent_cb), provider);
Packit 1f69a5
Packit 1f69a5
  devices = g_udev_client_query_by_subsystem (client, "video4linux");
Packit 1f69a5
Packit 1f69a5
  while (devices) {
Packit 1f69a5
    GUdevDevice *udev_device = devices->data;
Packit 1f69a5
    GstDevice *gstdev;
Packit 1f69a5
Packit 1f69a5
    devices = g_list_remove (devices, udev_device);
Packit 1f69a5
Packit 1f69a5
    if (g_udev_device_get_property_as_int (udev_device, "ID_V4L_VERSION") == 2) {
Packit 1f69a5
      gstdev =
Packit 1f69a5
          gst_v4l2_device_provider_device_from_udev (provider, udev_device);
Packit 1f69a5
      if (gstdev)
Packit 1f69a5
        gst_device_provider_device_add (GST_DEVICE_PROVIDER (provider), gstdev);
Packit 1f69a5
    }
Packit 1f69a5
Packit 1f69a5
    g_object_unref (udev_device);
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (provider);
Packit 1f69a5
  provider->started = TRUE;
Packit 1f69a5
  g_cond_broadcast (&provider->started_cond);
Packit 1f69a5
  GST_OBJECT_UNLOCK (provider);
Packit 1f69a5
Packit 1f69a5
  g_main_loop_run (loop);
Packit 1f69a5
  g_main_loop_unref (loop);
Packit 1f69a5
Packit 1f69a5
  g_object_unref (client);
Packit 1f69a5
  g_main_context_unref (context);
Packit 1f69a5
Packit 1f69a5
  gst_object_unref (provider);
Packit 1f69a5
Packit 1f69a5
  return NULL;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
gst_v4l2_device_provider_start (GstDeviceProvider * provider)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider);
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (self);
Packit 1f69a5
  g_assert (self->context == NULL);
Packit 1f69a5
Packit 1f69a5
  self->context = g_main_context_new ();
Packit 1f69a5
  self->loop = g_main_loop_new (self->context, FALSE);
Packit 1f69a5
Packit 1f69a5
  self->thread = g_thread_new ("v4l2-device-provider", provider_thread,
Packit 1f69a5
      g_object_ref (self));
Packit 1f69a5
Packit 1f69a5
  while (self->started == FALSE)
Packit 1f69a5
    g_cond_wait (&self->started_cond, GST_OBJECT_GET_LOCK (self));
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_UNLOCK (self);
Packit 1f69a5
Packit 1f69a5
  return TRUE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_provider_stop (GstDeviceProvider * provider)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2DeviceProvider *self = GST_V4L2_DEVICE_PROVIDER (provider);
Packit 1f69a5
  GMainContext *context;
Packit 1f69a5
  GMainLoop *loop;
Packit 1f69a5
  GSource *idle_stop_source;
Packit 1f69a5
Packit 1f69a5
  GST_OBJECT_LOCK (self);
Packit 1f69a5
  context = self->context;
Packit 1f69a5
  loop = self->loop;
Packit 1f69a5
  self->context = NULL;
Packit 1f69a5
  self->loop = NULL;
Packit 1f69a5
  GST_OBJECT_UNLOCK (self);
Packit 1f69a5
Packit 1f69a5
  if (!context || !loop)
Packit 1f69a5
    return;
Packit 1f69a5
Packit 1f69a5
  idle_stop_source = g_idle_source_new ();
Packit 1f69a5
  g_source_set_callback (idle_stop_source, (GSourceFunc) g_main_loop_quit, loop,
Packit 1f69a5
      (GDestroyNotify) g_main_loop_unref);
Packit 1f69a5
  g_source_attach (idle_stop_source, context);
Packit 1f69a5
  g_source_unref (idle_stop_source);
Packit 1f69a5
  g_main_context_unref (context);
Packit 1f69a5
Packit 1f69a5
  g_thread_join (self->thread);
Packit 1f69a5
  self->thread = NULL;
Packit 1f69a5
  self->started = FALSE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
#endif
Packit 1f69a5
Packit 1f69a5
enum
Packit 1f69a5
{
Packit 1f69a5
  PROP_DEVICE_PATH = 1,
Packit 1f69a5
};
Packit 1f69a5
Packit 1f69a5
G_DEFINE_TYPE (GstV4l2Device, gst_v4l2_device, GST_TYPE_DEVICE);
Packit 1f69a5
Packit 1f69a5
static void gst_v4l2_device_get_property (GObject * object, guint prop_id,
Packit 1f69a5
    GValue * value, GParamSpec * pspec);
Packit 1f69a5
static void gst_v4l2_device_set_property (GObject * object, guint prop_id,
Packit 1f69a5
    const GValue * value, GParamSpec * pspec);
Packit 1f69a5
static void gst_v4l2_device_finalize (GObject * object);
Packit 1f69a5
static GstElement *gst_v4l2_device_create_element (GstDevice * device,
Packit 1f69a5
    const gchar * name);
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_class_init (GstV4l2DeviceClass * klass)
Packit 1f69a5
{
Packit 1f69a5
  GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
Packit 1f69a5
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit 1f69a5
Packit 1f69a5
  dev_class->create_element = gst_v4l2_device_create_element;
Packit 1f69a5
Packit 1f69a5
  object_class->get_property = gst_v4l2_device_get_property;
Packit 1f69a5
  object_class->set_property = gst_v4l2_device_set_property;
Packit 1f69a5
  object_class->finalize = gst_v4l2_device_finalize;
Packit 1f69a5
Packit 1f69a5
  g_object_class_install_property (object_class, PROP_DEVICE_PATH,
Packit 1f69a5
      g_param_spec_string ("device-path", "Device Path",
Packit 1f69a5
          "The Path of the device node", "",
Packit 1f69a5
          G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_init (GstV4l2Device * device)
Packit 1f69a5
{
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_finalize (GObject * object)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Device *device = GST_V4L2_DEVICE (object);
Packit 1f69a5
Packit 1f69a5
  g_free (device->device_path);
Packit 1f69a5
  g_free (device->syspath);
Packit 1f69a5
Packit 1f69a5
  G_OBJECT_CLASS (gst_v4l2_device_parent_class)->finalize (object);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstElement *
Packit 1f69a5
gst_v4l2_device_create_element (GstDevice * device, const gchar * name)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Device *v4l2_dev = GST_V4L2_DEVICE (device);
Packit 1f69a5
  GstElement *elem;
Packit 1f69a5
Packit 1f69a5
  elem = gst_element_factory_make (v4l2_dev->element, name);
Packit 1f69a5
  g_object_set (elem, "device", v4l2_dev->device_path, NULL);
Packit 1f69a5
Packit 1f69a5
  return elem;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
static GstV4l2Device *
Packit 1f69a5
gst_v4l2_device_new (const gchar * device_path, const gchar * device_name,
Packit 1f69a5
    GstCaps * caps, GstV4l2DeviceType type, GstStructure * props)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Device *gstdev;
Packit 1f69a5
  const gchar *element = NULL;
Packit 1f69a5
  const gchar *klass = NULL;
Packit 1f69a5
Packit 1f69a5
  g_return_val_if_fail (device_path, NULL);
Packit 1f69a5
  g_return_val_if_fail (device_name, NULL);
Packit 1f69a5
  g_return_val_if_fail (caps, NULL);
Packit 1f69a5
Packit 1f69a5
  switch (type) {
Packit 1f69a5
    case GST_V4L2_DEVICE_TYPE_SOURCE:
Packit 1f69a5
      element = "v4l2src";
Packit 1f69a5
      klass = "Video/Source";
Packit 1f69a5
      break;
Packit 1f69a5
    case GST_V4L2_DEVICE_TYPE_SINK:
Packit 1f69a5
      element = "v4l2sink";
Packit 1f69a5
      klass = "Video/Sink";
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      g_assert_not_reached ();
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  gstdev = g_object_new (GST_TYPE_V4L2_DEVICE, "device-path", device_path,
Packit 1f69a5
      "display-name", device_name, "caps", caps, "device-class", klass,
Packit 1f69a5
      "properties", props, NULL);
Packit 1f69a5
Packit 1f69a5
  gstdev->element = element;
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
  return gstdev;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_get_property (GObject * object, guint prop_id,
Packit 1f69a5
    GValue * value, GParamSpec * pspec)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Device *device;
Packit 1f69a5
Packit 1f69a5
  device = GST_V4L2_DEVICE_CAST (object);
Packit 1f69a5
Packit 1f69a5
  switch (prop_id) {
Packit 1f69a5
    case PROP_DEVICE_PATH:
Packit 1f69a5
      g_value_set_string (value, device->device_path);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
static void
Packit 1f69a5
gst_v4l2_device_set_property (GObject * object, guint prop_id,
Packit 1f69a5
    const GValue * value, GParamSpec * pspec)
Packit 1f69a5
{
Packit 1f69a5
  GstV4l2Device *device;
Packit 1f69a5
Packit 1f69a5
  device = GST_V4L2_DEVICE_CAST (object);
Packit 1f69a5
Packit 1f69a5
  switch (prop_id) {
Packit 1f69a5
    case PROP_DEVICE_PATH:
Packit 1f69a5
      device->device_path = g_value_dup_string (value);
Packit 1f69a5
      break;
Packit 1f69a5
    default:
Packit 1f69a5
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
}